You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2106 lines
46 KiB
2106 lines
46 KiB
<template>
|
|
<div class="homepage">
|
|
<img src="../../../assets/qilin.webp" alt="麒麟" class="hllogo" />
|
|
|
|
<!-- 添加worldcup音频元素 -->
|
|
<audio ref="worldcupAudioRef" :src="worldcup" preload="auto" loop></audio>
|
|
<!-- 添加dong音频元素 -->
|
|
<audio ref="dongAudioRef" :src="dong" preload="auto"></audio>
|
|
|
|
<div ref="qipaoTextRef" class="qipao">{{ qipaoText }}</div>
|
|
|
|
<div class="leftBar">
|
|
<el-scrollbar id="prizeBar">
|
|
<ul class="prize-list">
|
|
<li
|
|
v-for="item in prizes"
|
|
:key="item.type"
|
|
:id="`prize-item-${item.type}`"
|
|
:class="['prize-item']"
|
|
@click="lookPrize(item)"
|
|
>
|
|
<div
|
|
v-if="item.isLook"
|
|
style="display: flex; width: 100%; height: 100%"
|
|
>
|
|
<span></span><span></span><span></span><span></span>
|
|
<div class="prize-img">
|
|
<img :src="item.imageUrl" :alt="item.title" />
|
|
</div>
|
|
<div class="prize-text">
|
|
<div class="prize-title">
|
|
<div class="level">
|
|
{{ item.gradeName }}
|
|
</div>
|
|
{{ item.prizeName }}
|
|
</div>
|
|
<div class="prize-count">
|
|
<div class="progress">
|
|
<div
|
|
:id="`prize-bar-${item.type}`"
|
|
class="progress-bar progress-bar-danger progress-bar-striped active"
|
|
style="width: 100%"
|
|
></div>
|
|
</div>
|
|
<div
|
|
:id="`prize-count-${item.type}`"
|
|
class="prize-count-left"
|
|
>
|
|
{{ item.leftCount }}/{{ item.count }}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div v-else style="display: flex; width: 100%; height: 100%">
|
|
<img
|
|
src="../../../assets/img/待揭秘.png"
|
|
alt="待揭秘"
|
|
class="readyLook"
|
|
/>
|
|
</div>
|
|
</li>
|
|
</ul>
|
|
</el-scrollbar>
|
|
<div v-if="!isOpen">
|
|
<div class="getPrizeName" @click="openGetPrize()">
|
|
<img src="../../../assets/img/展开.png" alt="展开" class="open" />
|
|
获奖名单
|
|
</div>
|
|
</div>
|
|
<div v-else>
|
|
<div class="dgetPrizeName">
|
|
<img
|
|
src="../../../assets/img/展开.png"
|
|
alt="展开"
|
|
class="close"
|
|
@click="closeGetPrize()"
|
|
/>
|
|
<div class="tableHead">
|
|
<div class="tableHead1">HomilyID</div>
|
|
<div class="tableHead2">奖项</div>
|
|
<div class="gradient-line"></div>
|
|
</div>
|
|
<el-scrollbar class="tableBody">
|
|
<div v-for="item in getPrizeUserList" :key="item">
|
|
<div class="tableItem">
|
|
<div class="tableItem1">
|
|
{{ item.jwcode }}
|
|
</div>
|
|
<div class="tableItem2">
|
|
{{ item.gradeName }}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</el-scrollbar>
|
|
<div class="tableFoot">
|
|
<span @click="leftPage()" id="leftPage" class="leftPage"><</span>
|
|
{{ currentPage }}/<span>{{ totalPage }}</span>
|
|
<span @click="rightPage()" id="rightPage" class="rightPage">></span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="container">
|
|
<div ref="threeContainer" class="three-container"></div>
|
|
|
|
<!-- 分页指示器 -->
|
|
<div v-if="pageMaxIndex > 1" class="page-indicator">
|
|
第 {{ pageIndex + 1 }} 页 / 共 {{ pageMaxIndex }} 页
|
|
</div>
|
|
</div>
|
|
|
|
<div id="menu">
|
|
<div id="enter" ref="enterRef" @click="enterLottery()" class="btn">
|
|
进入抽奖
|
|
</div>
|
|
|
|
<div id="lotteryBar" ref="lotteryBarRef" class="none">
|
|
<div v-if="isBackApi">
|
|
<div class="btn">{{ cjText }}</div>
|
|
</div>
|
|
<div v-else>
|
|
<div id="lottery" ref="lotteryRef" @click="lotteryBtn()" class="btn">
|
|
{{ cjText }}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { ref, onMounted, reactive, nextTick } from "vue";
|
|
import { useRouter } from "vue-router";
|
|
import * as THREE from "three";
|
|
import axios from "axios";
|
|
import "../../../assets/css/animate.min.css";
|
|
import { resetPrize } from "../../../utils/prizeList";
|
|
import { NUMBER_MATRIX } from "../../../utils/config";
|
|
import { CSS3DObject, CSS3DRenderer } from "../../../utils/CSS3DRenderer.js";
|
|
import { TrackballControls } from "../../../utils/TrackballControls.js";
|
|
import TWEEN from "@tweenjs/tween.js";
|
|
import worldcup from "../../../assets/worldcup.mp3";
|
|
import dong from "../../../assets/dong.mp3";
|
|
|
|
import {
|
|
getPrizeListApi,
|
|
getUserListApi,
|
|
getGetPrizeUserListApi,
|
|
startLotteryApi,
|
|
} from "../../../api/API";
|
|
|
|
// 常量
|
|
const ROTATE_TIME = 10000; //旋转动画的总时长
|
|
const ROTATE_LOOP = 1000;
|
|
const BASE_HEIGHT = 1080; //高度
|
|
|
|
// 按钮控制
|
|
const enterRef = ref(null); //进入抽奖按钮
|
|
const lotteryBarRef = ref(null); //开始抽奖元素组(显示控制)
|
|
const lotteryRef = ref(null); //开始抽奖按钮(文字控制 )
|
|
|
|
//3D相关变量
|
|
// 当前的比例
|
|
let Resolution = 0.9;
|
|
//总卡片数
|
|
let TOTAL_CARDS;
|
|
// 高度卡片数
|
|
let ROW_COUNT = 7;
|
|
// 宽度卡片数
|
|
let COLUMN_COUNT = 21;
|
|
// 高亮卡片数组
|
|
let HIGHLIGHT_CELL = [];
|
|
// 其他变量
|
|
let camera,
|
|
scene,
|
|
renderer,
|
|
controls,
|
|
threeDCards = [],
|
|
targets = {
|
|
table: [],
|
|
sphere: [],
|
|
};
|
|
// 动画对象
|
|
let rotateObj;
|
|
// 控制旋转
|
|
let rotate = false;
|
|
|
|
//奖品列表
|
|
const prizes = ref([]);
|
|
//每个奖品每次抽取的数目
|
|
let EACH_COUNT = [];
|
|
|
|
const users = ref([]);
|
|
const getPrizeUsers = ref([]);
|
|
//判断是否正在抽奖
|
|
let isLotting = false;
|
|
const setLotteryStatus = (status = false) => {
|
|
isLotting = status;
|
|
};
|
|
|
|
let selectedCardIndex = [];
|
|
let interval;
|
|
// 当前抽的奖项,从最低奖开始抽,直到抽到大奖
|
|
let currentPrizeIndex;
|
|
const currentPrize = ref({});
|
|
|
|
let currentLuckys = [];
|
|
let prizeElement = {};
|
|
|
|
const qipaoText = ref("");
|
|
const qipaoTextRef = ref(null);
|
|
|
|
const worldcupAudioRef = ref(null);
|
|
const dongAudioRef = ref(null);
|
|
// 播放worldcup音频
|
|
const playWorldcupAudio = () => {
|
|
if (worldcupAudioRef.value) {
|
|
worldcupAudioRef.value.currentTime = 0; // 重置播放位置
|
|
worldcupAudioRef.value.play().catch((error) => {
|
|
console.log("音频播放失败:", error);
|
|
});
|
|
}
|
|
};
|
|
|
|
// 暂停worldcup音频
|
|
const pauseWorldcupAudio = () => {
|
|
if (worldcupAudioRef.value) {
|
|
worldcupAudioRef.value.pause();
|
|
}
|
|
};
|
|
|
|
const playDongAudio = () => {
|
|
if (dongAudioRef.value) {
|
|
dongAudioRef.value.currentTime = 0; // 重置播放位置
|
|
dongAudioRef.value.play().catch((error) => {
|
|
console.log("音频播放失败:", error);
|
|
});
|
|
}
|
|
};
|
|
|
|
// 暂停dong音频
|
|
const pauseDongAudio = () => {
|
|
if (dongAudioRef.value) {
|
|
dongAudioRef.value.pause();
|
|
}
|
|
};
|
|
|
|
const addQipao = (text) => {
|
|
qipaoTextRef.value.style.display = "block";
|
|
qipaoTextRef.value.style.opacity = "1";
|
|
|
|
qipaoText.value = text;
|
|
setTimeout(() => {
|
|
// 设置过渡效果
|
|
qipaoTextRef.value.style.transition = "opacity 0.5s ease-out";
|
|
// 开始渐隐
|
|
qipaoTextRef.value.style.opacity = "0";
|
|
// 动画完成后隐藏元素
|
|
setTimeout(() => {
|
|
qipaoTextRef.value.style.display = "none";
|
|
}, 800);
|
|
}, 1000);
|
|
};
|
|
|
|
const getPrizeUserList = ref([]);
|
|
const isOpen = ref(false);
|
|
|
|
const pageObj = ref({
|
|
pageNum: 1,
|
|
pageSize: 14,
|
|
});
|
|
|
|
const currentPage = ref(1);
|
|
const totalPage = ref(10);
|
|
|
|
const openGetPrize = async () => {
|
|
if (!prizes.value[prizes.value.length - 1].isLook) {
|
|
addQipao("请先揭晓奖品。");
|
|
return;
|
|
}
|
|
|
|
let res = await getGetPrizeUserListApi(pageObj.value);
|
|
getPrizeUserList.value = res.data.list;
|
|
currentPage.value = res.data.pageNum;
|
|
totalPage.value = res.data.pages;
|
|
isOpen.value = true;
|
|
// console.log("currentPrize", currentPrize.value);
|
|
prizes.value.forEach((item) => {
|
|
// console.log("item", item);
|
|
if (item.type != currentPrize.value.type) {
|
|
let box = document.querySelector(`#prize-item-${item.type}`);
|
|
box.style.display = "none";
|
|
}
|
|
});
|
|
let scroll = document.getElementById("prizeBar");
|
|
// scroll.style.height = "110px";
|
|
};
|
|
|
|
const closeGetPrize = () => {
|
|
isOpen.value = false;
|
|
prizes.value.forEach((item) => {
|
|
// console.log("item", item);
|
|
if (item.type != currentPrize.value.type) {
|
|
let box = document.querySelector(`#prize-item-${item.type}`);
|
|
box.style.display = "flex";
|
|
}
|
|
});
|
|
// let scroll = document.getElementById("prizeBar");
|
|
// scroll.style.height = "650px";
|
|
};
|
|
|
|
const leftPage = async (item) => {
|
|
if (currentPage.value == 1) {
|
|
return;
|
|
}
|
|
if (currentPage.value == totalPage.value) {
|
|
const rightPageBtn = document.getElementById("rightPage");
|
|
rightPageBtn.style.cursor = "pointer";
|
|
rightPageBtn.style.setProperty(
|
|
"background",
|
|
"linear-gradient(90deg, #ff9800 0%, #ff5722 100%)",
|
|
"important"
|
|
);
|
|
}
|
|
currentPage.value--;
|
|
pageObj.value.pageNum = currentPage;
|
|
let res = await getGetPrizeUserListApi(pageObj.value);
|
|
getPrizeUserList.value = res.data.list;
|
|
currentPage.value = res.data.pageNum;
|
|
|
|
if (currentPage.value == 1) {
|
|
const leftPageBtn = document.getElementById("leftPage");
|
|
leftPageBtn.style.cursor = "not-allowed";
|
|
leftPageBtn.style.background = "#ccc";
|
|
}
|
|
};
|
|
const rightPage = async (item) => {
|
|
if (currentPage.value == totalPage.value) {
|
|
return;
|
|
}
|
|
|
|
if (currentPage.value == 1) {
|
|
const leftPageBtn = document.getElementById("leftPage");
|
|
console.log("leftPageBtn", leftPageBtn);
|
|
leftPageBtn.style.cursor = "pointer";
|
|
leftPageBtn.style.setProperty(
|
|
"background",
|
|
"linear-gradient(90deg, #ff9800 0%, #ff5722 100%)",
|
|
"important"
|
|
);
|
|
}
|
|
|
|
currentPage.value++;
|
|
pageObj.value.pageNum = currentPage;
|
|
let res = await getGetPrizeUserListApi(pageObj.value);
|
|
getPrizeUserList.value = res.data.list;
|
|
currentPage.value = res.data.pageNum;
|
|
|
|
if (currentPage.value == totalPage.value) {
|
|
const rightPageBtn = document.getElementById("rightPage");
|
|
rightPageBtn.style.cursor = "not-allowed";
|
|
rightPageBtn.style.background = "#ccc";
|
|
}
|
|
};
|
|
|
|
//揭示奖品
|
|
const lookPrize = async (item) => {
|
|
// 未进入抽奖禁止揭晓
|
|
if (!joinLottery) {
|
|
addQipao("请先进入抽奖。");
|
|
return;
|
|
}
|
|
// 如果已经揭示,那返回
|
|
if (item.isLook) return;
|
|
//最低级的可以直接揭晓
|
|
if (
|
|
currentPrize.value.type == prizes.value[prizes.value.length - 1].type &&
|
|
item.type == currentPrize.value.type
|
|
) {
|
|
let currentBox = document.querySelector(`#prize-item-${item.type}`);
|
|
|
|
currentBox && currentBox.classList.add("shine");
|
|
//点击揭晓
|
|
item.isLook = true;
|
|
} else if (
|
|
!isLotting && //未在抽奖状态
|
|
currentPrize.value.isLook &&
|
|
currentPrize.value.leftCount == 0 && //当前奖项已抽完
|
|
prizes.value[currentPrizeIndex - 1] == item //点击的奖项是当前奖项的下一个
|
|
) {
|
|
currentPrize.value = item;
|
|
currentPrizeIndex--;
|
|
let lastIndex = -1;
|
|
for (let i = prizes.value.length - 1; i >= 0; i--) {
|
|
if (prizes.value[i].type == item.type) {
|
|
if (i != prizes.value.length - 1) {
|
|
lastIndex = i + 1;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
if (lastIndex != -1) {
|
|
let lastPrize = prizes.value[lastIndex];
|
|
// console.log("lastPrize", lastPrize);
|
|
let lastBox = document.querySelector(`#prize-item-${lastPrize.type}`);
|
|
lastBox.classList.remove("shine");
|
|
lastBox.classList.add("done");
|
|
|
|
let currentBox = document.querySelector(`#prize-item-${item.type}`);
|
|
|
|
currentBox && currentBox.classList.add("shine");
|
|
}
|
|
//点击揭晓
|
|
item.isLook = true;
|
|
}
|
|
await nextTick();
|
|
setPrizeData(currentPrizeIndex);
|
|
};
|
|
|
|
function setPrizeData(currentPrizeIndex, isInit) {
|
|
// console.log("prizes", prizes.value);
|
|
// let currentPrize = prizes.value[currentPrizeIndex];
|
|
let type = currentPrize.value.type;
|
|
let elements = prizeElement[type];
|
|
|
|
let count = currentPrize.value.leftCount;
|
|
let totalCount = currentPrize.value.count;
|
|
|
|
if (!elements || !elements.bar || !elements.text) {
|
|
elements = {
|
|
box: document.querySelector(`#prize-item-${type}`),
|
|
bar: document.querySelector(`#prize-bar-${type}`),
|
|
text: document.querySelector(`#prize-count-${type}`),
|
|
};
|
|
}
|
|
|
|
if (isInit) {
|
|
for (let i = prizes.value.length - 1; i > currentPrizeIndex; i--) {
|
|
let type = prizes.value[i]["type"];
|
|
document.querySelector(`#prize-item-${type}`).className =
|
|
"prize-item done";
|
|
document.querySelector(`#prize-bar-${type}`).style.width = "0";
|
|
document.querySelector(`#prize-count-${type}`).textContent =
|
|
"0" + "/" + prizes.value[i]["count"];
|
|
}
|
|
}
|
|
|
|
console.log("count", count);
|
|
console.log("totalCount", totalCount);
|
|
|
|
let percent = (count / totalCount).toFixed(2);
|
|
if (elements.bar) {
|
|
elements.bar.style.width = percent * 100 + "%";
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 初始化所有DOM
|
|
*/
|
|
const pageIndex = ref(0);
|
|
const pageMaxIndex = ref(0);
|
|
const cardsPerPage = 10; // 每页显示的卡片数量
|
|
let isPageTransitioning = false; // 防止页面切换时的重复操作
|
|
// 全局变量存储当前选中的卡片索引数组
|
|
let globalCardIndexes = [];
|
|
|
|
const initAll = async () => {
|
|
const [prizeList, userList] = await Promise.all([
|
|
getPrizeListApi(),
|
|
getUserListApi(),
|
|
]);
|
|
console.log("hxl-cj调用一次接口", prizeList);
|
|
// 奖品列表
|
|
prizes.value = prizeList.data;
|
|
// 用户列表
|
|
users.value = userList.data;
|
|
prizes.value.forEach((item, index) => {
|
|
item.type = index;
|
|
item.count = item.amount;
|
|
item.leftCount = item.remainNum; //剩余次数(用于计算奖品下方的进度条的百分比)
|
|
item.hasCount = item.amount; //已抽次数(用于计算出奖)
|
|
item.isLook = false; //
|
|
EACH_COUNT.push(item.perWin);
|
|
});
|
|
console.log("prizes", prizes.value);
|
|
console.log("EACH_COUNT", EACH_COUNT);
|
|
|
|
HIGHLIGHT_CELL = createHighlight();
|
|
|
|
TOTAL_CARDS = ROW_COUNT * COLUMN_COUNT;
|
|
|
|
currentPrizeIndex = prizes.value.length - 1;
|
|
currentPrize.value = prizes.value[currentPrizeIndex];
|
|
|
|
await nextTick();
|
|
setPrizeData(currentPrizeIndex, true);
|
|
|
|
initCards();
|
|
// startMaoPao();
|
|
animate();
|
|
shineCard();
|
|
// window.AJAX({
|
|
// url: "/getUsers",
|
|
// success(data) {},
|
|
// });
|
|
};
|
|
|
|
const initCards = () => {
|
|
let member = users.value.slice(),
|
|
showCards = [],
|
|
length = member.length;
|
|
|
|
let isBold = false;
|
|
let index = 0;
|
|
let totalMember = member.length;
|
|
let position = {
|
|
x: (140 * COLUMN_COUNT - 20) / 2,
|
|
y: (180 * ROW_COUNT - 20) / 2,
|
|
};
|
|
|
|
camera = new THREE.PerspectiveCamera(
|
|
40,
|
|
window.innerWidth / window.innerHeight,
|
|
1,
|
|
10000
|
|
);
|
|
camera.position.z = 3000;
|
|
|
|
scene = new THREE.Scene();
|
|
|
|
for (let i = 0; i < ROW_COUNT; i++) {
|
|
for (let j = 0; j < COLUMN_COUNT; j++) {
|
|
isBold = HIGHLIGHT_CELL.includes(j + "-" + i);
|
|
var element = createCard(member[index % length], isBold, index);
|
|
|
|
var object = new CSS3DObject(element);
|
|
object.position.x = Math.random() * 4000 - 2000;
|
|
object.position.y = Math.random() * 4000 - 2000;
|
|
object.position.z = Math.random() * 4000 - 2000;
|
|
scene.add(object);
|
|
threeDCards.push(object);
|
|
//
|
|
|
|
var object = new THREE.Object3D();
|
|
object.position.x = j * 155 - position.x;
|
|
object.position.y = -(i * 195) + position.y;
|
|
targets.table.push(object);
|
|
index++;
|
|
}
|
|
}
|
|
|
|
// sphere
|
|
|
|
var vector = new THREE.Vector3();
|
|
|
|
for (var i = 0, l = threeDCards.length; i < l; i++) {
|
|
var phi = Math.acos(-1 + (2 * i) / l);
|
|
var theta = Math.sqrt(l * Math.PI) * phi;
|
|
var object = new THREE.Object3D();
|
|
object.position.setFromSphericalCoords(800 * Resolution, phi, theta);
|
|
vector.copy(object.position).multiplyScalar(2);
|
|
object.lookAt(vector);
|
|
targets.sphere.push(object);
|
|
}
|
|
|
|
renderer = new CSS3DRenderer();
|
|
renderer.setSize(window.innerWidth * 1, window.innerHeight * 0.9);
|
|
renderer.domElement.style.margin = "7% 0 0 1%";
|
|
// document.getElementById("container").appendChild(renderer.domElement);
|
|
|
|
if (threeContainer.value) {
|
|
threeContainer.value.appendChild(renderer.domElement);
|
|
}
|
|
|
|
//
|
|
|
|
controls = new TrackballControls(camera, renderer.domElement);
|
|
controls.rotateSpeed = 0.5;
|
|
controls.minDistance = 500;
|
|
controls.maxDistance = 6000;
|
|
controls.addEventListener("change", render);
|
|
|
|
switchScreen("enter");
|
|
};
|
|
|
|
// 判断是否进入抽奖
|
|
let joinLottery = false;
|
|
// 进入抽奖
|
|
const enterLottery = () => {
|
|
joinLottery = true;
|
|
removeHighlight();
|
|
// rotate = !rotate;
|
|
rotate = true;
|
|
switchScreen("lottery");
|
|
};
|
|
|
|
function switchScreen(type) {
|
|
switch (type) {
|
|
case "enter":
|
|
if (enterRef.value) {
|
|
enterRef.value.classList.remove("none");
|
|
}
|
|
if (lotteryBarRef.value) {
|
|
lotteryBarRef.value.classList.add("none");
|
|
}
|
|
transform(targets.table, 2000);
|
|
break;
|
|
default:
|
|
if (enterRef.value) {
|
|
enterRef.value.classList.add("none");
|
|
}
|
|
if (lotteryBarRef.value) {
|
|
lotteryBarRef.value.classList.remove("none");
|
|
}
|
|
transform(targets.sphere, 2000);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 创建元素
|
|
*/
|
|
const createElement = (css, text) => {
|
|
let dom = document.createElement("div");
|
|
dom.className = css || "";
|
|
dom.innerHTML = text || "";
|
|
return dom;
|
|
};
|
|
|
|
/**
|
|
* 创建名牌
|
|
*/
|
|
const createCard = (user, isBold, id) => {
|
|
var element = createElement();
|
|
element.id = "card-" + id;
|
|
element.style.display = "flex";
|
|
element.style.alignItems = "center";
|
|
element.style.justifyContent = "center";
|
|
if (isBold) {
|
|
element.className = "element lightitem";
|
|
element.classList.add("highlight");
|
|
} else {
|
|
element.className = "element";
|
|
// element.style.backgroundColor =
|
|
// "rgba(255,170,22," + (Math.random() * 0.7 + 0.25) + ")";
|
|
element.style.backgroundColor = "rgba(255,170,22,1)";
|
|
element.style.border = "2px solid rgba(255, 255, 255, 1)";
|
|
}
|
|
|
|
element.appendChild(createElement("name", user.jwcode));
|
|
|
|
return element;
|
|
};
|
|
|
|
function removeHighlight() {
|
|
document.querySelectorAll(".highlight").forEach((node) => {
|
|
node.classList.remove("highlight");
|
|
});
|
|
}
|
|
|
|
function addHighlight() {
|
|
document.querySelectorAll(".lightitem").forEach((node) => {
|
|
node.classList.add("highlight");
|
|
});
|
|
}
|
|
|
|
/**
|
|
* 渲染地球等
|
|
*/
|
|
function transform(targets, duration) {
|
|
// TWEEN.removeAll();
|
|
for (var i = 0; i < threeDCards.length; i++) {
|
|
var object = threeDCards[i];
|
|
var target = targets[i];
|
|
|
|
new TWEEN.Tween(object.position)
|
|
.to(
|
|
{
|
|
x: target.position.x,
|
|
y: target.position.y,
|
|
z: target.position.z,
|
|
},
|
|
Math.random() * duration + duration
|
|
)
|
|
.easing(TWEEN.Easing.Exponential.InOut)
|
|
.start();
|
|
|
|
new TWEEN.Tween(object.rotation)
|
|
.to(
|
|
{
|
|
x: target.rotation.x,
|
|
y: target.rotation.y,
|
|
z: target.rotation.z,
|
|
},
|
|
Math.random() * duration + duration
|
|
)
|
|
.easing(TWEEN.Easing.Exponential.InOut)
|
|
.start();
|
|
}
|
|
|
|
new TWEEN.Tween(this)
|
|
.to({}, duration * 2)
|
|
.onUpdate(render)
|
|
.start();
|
|
}
|
|
|
|
function rotateBall() {
|
|
return new Promise((resolve, reject) => {
|
|
scene.rotation.y = 0;
|
|
rotateObj = new TWEEN.Tween(scene.rotation);
|
|
rotateObj
|
|
.to(
|
|
{
|
|
y: Math.PI * 6 * ROTATE_LOOP,
|
|
},
|
|
ROTATE_TIME * ROTATE_LOOP
|
|
)
|
|
.onUpdate(render)
|
|
// .easing(TWEEN.Easing.Linear)
|
|
.start()
|
|
.onStop(() => {
|
|
scene.rotation.y = 0;
|
|
resolve();
|
|
})
|
|
.onComplete(() => {
|
|
resolve();
|
|
});
|
|
});
|
|
}
|
|
|
|
function animate() {
|
|
// 让场景通过x轴或者y轴旋转
|
|
// rotate && (scene.rotation.y += 0.088);
|
|
|
|
requestAnimationFrame(animate);
|
|
TWEEN.update();
|
|
controls.update();
|
|
|
|
// 渲染循环
|
|
// render();
|
|
}
|
|
|
|
function render() {
|
|
renderer.render(scene, camera);
|
|
}
|
|
|
|
const threeContainer = ref(null);
|
|
function selectCard(duration = 600) {
|
|
return new Promise((resolve) => {
|
|
const width = 160;
|
|
|
|
// 计算总页数
|
|
pageMaxIndex.value = Math.ceil(currentLuckys.length / cardsPerPage);
|
|
pageIndex.value = 0;
|
|
|
|
// 为每页计算位置信息
|
|
const pageLocates = [];
|
|
|
|
for (let page = 0; page < pageMaxIndex.value; page++) {
|
|
const startIndex = page * cardsPerPage;
|
|
const endIndex = Math.min(
|
|
(page + 1) * cardsPerPage,
|
|
currentLuckys.length
|
|
);
|
|
const pageCount = endIndex - startIndex;
|
|
|
|
const pageLocate = [];
|
|
|
|
// 根据当前页的人数决定排列方式
|
|
if (pageCount > 5) {
|
|
// 大于5个分两排显示(与抽10人时的排列相同)
|
|
const yPosition = [-75, 120];
|
|
const mid = Math.ceil(pageCount / 2);
|
|
let tag = -(mid - 1) / 2;
|
|
|
|
for (let i = 0; i < mid; i++) {
|
|
pageLocate.push({
|
|
x: tag * width,
|
|
y: yPosition[0],
|
|
});
|
|
tag++;
|
|
}
|
|
|
|
tag = -(pageCount - mid - 1) / 2;
|
|
for (let i = mid; i < pageCount; i++) {
|
|
pageLocate.push({
|
|
x: tag * width,
|
|
y: yPosition[1],
|
|
});
|
|
tag++;
|
|
}
|
|
} else {
|
|
// 小于等于5个一排显示(与抽不足10人时的排列相同)
|
|
let tag = -(pageCount - 1) / 2;
|
|
for (let i = 0; i < pageCount; i++) {
|
|
pageLocate.push({
|
|
x: tag * width,
|
|
y: 0,
|
|
});
|
|
tag++;
|
|
}
|
|
}
|
|
|
|
pageLocates.push(pageLocate);
|
|
}
|
|
|
|
// console.log("pageLocates calculated:", pageLocates);
|
|
|
|
// 初始化所有卡片位置(隐藏超出第一页的卡片)
|
|
selectedCardIndex.forEach((cardIndex, index) => {
|
|
changeSelectedCard(cardIndex, currentLuckys[index]);
|
|
const object = threeDCards[cardIndex];
|
|
|
|
// 计算卡片应该在第几页
|
|
const cardPage = Math.floor(index / cardsPerPage);
|
|
const isVisible = cardPage === 0;
|
|
|
|
// 计算在当前页中的索引
|
|
const pageNowIndex = index % cardsPerPage;
|
|
const pageLocate = pageLocates[cardPage][pageNowIndex];
|
|
|
|
new TWEEN.Tween(object.position)
|
|
.to(
|
|
{
|
|
x: isVisible ? pageLocate.x : pageLocate.x,
|
|
y: isVisible ? pageLocate.y : pageLocate.y + 1000, // 隐藏的卡片移到下方
|
|
z: 2100,
|
|
},
|
|
Math.random() * duration + duration
|
|
)
|
|
.easing(TWEEN.Easing.Exponential.InOut)
|
|
.start();
|
|
|
|
new TWEEN.Tween(object.rotation)
|
|
.to(
|
|
{
|
|
x: 0,
|
|
y: 0,
|
|
z: 0,
|
|
},
|
|
Math.random() * duration + duration
|
|
)
|
|
.easing(TWEEN.Easing.Exponential.InOut)
|
|
.start();
|
|
|
|
object.element.classList.add("prize");
|
|
});
|
|
|
|
// 保存页面位置信息到全局变量,供switchPage使用
|
|
window.pageLocates = pageLocates;
|
|
|
|
new TWEEN.Tween({})
|
|
.to({}, duration * 2)
|
|
.onUpdate(() => render())
|
|
.start()
|
|
.onComplete(() => {
|
|
console.log("selectCard animation completed");
|
|
// 如果有多页,添加鼠标滚轮事件监听
|
|
if (pageMaxIndex.value > 1) {
|
|
// console.log("pageMaxIndex添加滚轮", pageMaxIndex.value);
|
|
// 添加滚轮事件监听
|
|
addWheelListener();
|
|
}
|
|
|
|
setLotteryStatus();
|
|
resolve();
|
|
});
|
|
});
|
|
}
|
|
|
|
// 分页切换函数
|
|
function switchPage(direction) {
|
|
if (isPageTransitioning || pageMaxIndex.value <= 1) return;
|
|
|
|
const newPage =
|
|
direction === "next" ? pageIndex.value + 1 : pageIndex.value - 1;
|
|
if (newPage < 0 || newPage >= pageMaxIndex.value) return;
|
|
|
|
isPageTransitioning = true;
|
|
const duration = 800;
|
|
|
|
// 使用保存的页面位置信息
|
|
const pageLocates = window.pageLocates;
|
|
if (!pageLocates) {
|
|
console.error("页面位置信息未找到");
|
|
isPageTransitioning = false;
|
|
return;
|
|
}
|
|
|
|
// 动画切换卡片位置
|
|
globalCardIndexes.forEach((cardIndex, index) => {
|
|
const object = threeDCards[cardIndex];
|
|
const cardPage = Math.floor(index / cardsPerPage);
|
|
const isVisible = cardPage === newPage;
|
|
const wasVisible = cardPage === pageIndex.value;
|
|
// 计算在当前页中的索引
|
|
const pageNowIndex = index % cardsPerPage;
|
|
const pageLocate = pageLocates[cardPage][pageNowIndex];
|
|
|
|
// console.log(
|
|
// "cardPage",
|
|
// cardPage,
|
|
// "pageNowIndex",
|
|
// pageNowIndex,
|
|
// "pageLocate",
|
|
// pageLocate
|
|
// );
|
|
|
|
// 根据切换方向决定动画效果
|
|
let targetY;
|
|
if (isVisible) {
|
|
// 当前页要显示的卡片
|
|
if (direction === "next") {
|
|
// 索引增大:从下方飞出
|
|
targetY = pageLocate.y;
|
|
} else {
|
|
// 索引减少:从上方飞出
|
|
targetY = pageLocate.y;
|
|
}
|
|
} else {
|
|
// 当前页要隐藏的卡片
|
|
if (direction === "next") {
|
|
// 索引增大:向上飞走
|
|
targetY = pageLocate.y + 1000;
|
|
} else {
|
|
// 索引减少:向下飞走
|
|
targetY = pageLocate.y - 1000;
|
|
}
|
|
}
|
|
|
|
// 设置起始位置
|
|
let startY;
|
|
if (wasVisible) {
|
|
// 当前页的卡片从当前位置开始
|
|
startY = object.position.y;
|
|
} else {
|
|
// 非当前页的卡片从隐藏位置开始
|
|
if (direction === "next") {
|
|
// 索引增大:从下方开始
|
|
startY = pageLocate.y - 1000;
|
|
} else {
|
|
// 索引减少:从上方开始
|
|
startY = pageLocate.y + 1000;
|
|
}
|
|
}
|
|
|
|
// 先设置起始位置
|
|
object.position.y = startY;
|
|
|
|
new TWEEN.Tween(object.position)
|
|
.to(
|
|
{
|
|
x: pageLocate.x,
|
|
y: targetY,
|
|
z: 2100,
|
|
},
|
|
duration
|
|
)
|
|
.easing(TWEEN.Easing.Cubic.InOut)
|
|
.start();
|
|
});
|
|
|
|
new TWEEN.Tween({})
|
|
.to({}, duration)
|
|
.onUpdate(() => render())
|
|
.onComplete(() => {
|
|
pageIndex.value = newPage;
|
|
isPageTransitioning = false;
|
|
console.log(
|
|
`切换到第 ${pageIndex.value + 1} 页,共 ${pageMaxIndex.value} 页`
|
|
);
|
|
})
|
|
.start();
|
|
}
|
|
|
|
// 鼠标滚轮事件处理
|
|
function handleWheel(event) {
|
|
if (isPageTransitioning || pageMaxIndex.value <= 1) return;
|
|
|
|
event.preventDefault();
|
|
|
|
if (event.deltaY > 0) {
|
|
// 向下滚动,显示下一页
|
|
switchPage("next");
|
|
} else if (event.deltaY < 0) {
|
|
// 向上滚动,显示上一页
|
|
switchPage("prev");
|
|
}
|
|
}
|
|
|
|
// 添加鼠标滚轮事件监听器
|
|
function addWheelListener() {
|
|
if (threeContainer.value) {
|
|
threeContainer.value.addEventListener("wheel", handleWheel, {
|
|
passive: false,
|
|
});
|
|
}
|
|
}
|
|
|
|
// 移除鼠标滚轮事件监听器
|
|
function removeWheelListener() {
|
|
if (threeContainer.value) {
|
|
threeContainer.value.removeEventListener("wheel", handleWheel);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 重置抽奖牌内容
|
|
*/
|
|
function resetCard(duration = 500) {
|
|
if (currentLuckys.length === 0) {
|
|
return Promise.resolve();
|
|
}
|
|
|
|
globalCardIndexes = [];
|
|
// 移除鼠标滚轮事件监听器
|
|
removeWheelListener();
|
|
|
|
// 重置分页状态
|
|
pageIndex.value = 0;
|
|
pageMaxIndex.value = 0;
|
|
isPageTransitioning = false;
|
|
|
|
// 清理保存的页面位置信息
|
|
if (window.pageLocates) {
|
|
delete window.pageLocates;
|
|
}
|
|
|
|
selectedCardIndex.forEach((index) => {
|
|
let object = threeDCards[index],
|
|
target = targets.sphere[index];
|
|
|
|
new TWEEN.Tween(object.position)
|
|
.to(
|
|
{
|
|
x: target.position.x,
|
|
y: target.position.y,
|
|
z: target.position.z,
|
|
},
|
|
Math.random() * duration + duration
|
|
)
|
|
.easing(TWEEN.Easing.Exponential.InOut)
|
|
.start();
|
|
|
|
new TWEEN.Tween(object.rotation)
|
|
.to(
|
|
{
|
|
x: target.rotation.x,
|
|
y: target.rotation.y,
|
|
z: target.rotation.z,
|
|
},
|
|
Math.random() * duration + duration
|
|
)
|
|
.easing(TWEEN.Easing.Exponential.InOut)
|
|
.start();
|
|
});
|
|
|
|
return new Promise((resolve, reject) => {
|
|
new TWEEN.Tween(this)
|
|
.to({}, duration * 2)
|
|
.onUpdate(render)
|
|
.start()
|
|
.onComplete(() => {
|
|
selectedCardIndex.forEach((index) => {
|
|
let object = threeDCards[index];
|
|
object.element.classList.remove("prize");
|
|
});
|
|
resolve();
|
|
});
|
|
});
|
|
}
|
|
|
|
const isBackApi = ref(false);
|
|
const cjText = ref("开始抽奖");
|
|
// 抽奖
|
|
const lotteryBtn = () => {
|
|
// console.log("isLotting", isLotting);
|
|
// console.log("currentPrize.value", currentPrize.value);
|
|
if (isLotting) {
|
|
stopLottery();
|
|
return;
|
|
}
|
|
|
|
if (!currentPrize.value.isLook) {
|
|
addQipao("请先揭秘礼品。");
|
|
return;
|
|
}
|
|
if (currentPrize.value.leftCount <= 0) {
|
|
addQipao("该礼品已抽取完毕,请揭秘下一个礼品。");
|
|
return;
|
|
}
|
|
|
|
// lotteryRef.value.innerHTML = "结束抽奖";
|
|
cjText.value = "结束抽奖";
|
|
|
|
isBackApi.value = true;
|
|
// 播放worldcup音频
|
|
playWorldcupAudio();
|
|
|
|
getPrizeUsers.value = [];
|
|
let params = {
|
|
gradeId: currentPrize.value.gradeId,
|
|
prizeId: currentPrize.value.prizeId,
|
|
perWin: currentPrize.value.perWin,
|
|
remainNum: currentPrize.value.leftCount,
|
|
};
|
|
// 异步调用API,不阻塞后续代码执行
|
|
startLotteryApi(params)
|
|
.then((res) => {
|
|
// API返回结果时赋值
|
|
getPrizeUsers.value = res.data.data || [];
|
|
isBackApi.value = false;
|
|
console.log("API返回结果:", res.data.data);
|
|
})
|
|
.catch((err) => {
|
|
isBackApi.value = false;
|
|
console.error("API调用失败:", err);
|
|
getPrizeUsers.value = [];
|
|
});
|
|
|
|
setLotteryStatus(true);
|
|
//更新剩余抽奖数目的数据显示
|
|
changePrize();
|
|
resetCard().then((res) => {
|
|
// 抽奖
|
|
lottery();
|
|
});
|
|
|
|
console.log("currentPrize", currentPrize.value);
|
|
|
|
const text = "正在抽取[" + currentPrize.value.prizeName + "],调整好姿势";
|
|
// addQipao(text);
|
|
};
|
|
/**
|
|
* 抽奖
|
|
*/
|
|
|
|
const lottery = () => {
|
|
rotateBall().then(() => {
|
|
// 将之前的记录置空
|
|
currentLuckys = [];
|
|
selectedCardIndex = [];
|
|
// 当前同时抽取的数目,当前奖品抽完还可以继续抽,但是不记录数据
|
|
|
|
for (let i = 0; i < getPrizeUsers.value.length; i++) {
|
|
console.log("111", getPrizeUsers.value[i]);
|
|
currentLuckys.push(getPrizeUsers.value[i]);
|
|
currentPrize.value.hasCount--;
|
|
|
|
//避免中奖者出现在同一个卡片上
|
|
let cardIndex = random(TOTAL_CARDS);
|
|
while (selectedCardIndex.includes(cardIndex)) {
|
|
cardIndex = random(TOTAL_CARDS);
|
|
}
|
|
selectedCardIndex.push(cardIndex);
|
|
|
|
if (currentPrize.value.hasCount === 0) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
selectCard(600);
|
|
});
|
|
};
|
|
|
|
const stopLottery = () => {
|
|
// lotteryRef.value.innerHTML = "开始抽奖";
|
|
cjText.value = "开始抽奖";
|
|
rotateObj.stop();
|
|
|
|
// 暂停worldcup音频
|
|
pauseWorldcupAudio();
|
|
playDongAudio();
|
|
};
|
|
|
|
const changePrize = async () => {
|
|
let type = currentPrize.value.type;
|
|
|
|
prizes.value[type].leftCount =
|
|
prizes.value[type].leftCount - EACH_COUNT[type] < 0
|
|
? 0
|
|
: prizes.value[type].leftCount - EACH_COUNT[type];
|
|
await nextTick();
|
|
// 修改左侧prize的数目和百分比
|
|
setPrizeData(currentPrizeIndex);
|
|
};
|
|
|
|
/**
|
|
* 随机抽奖
|
|
*/
|
|
function random(num) {
|
|
// Math.floor取到0-num-1之间数字的概率是相等的
|
|
return Math.floor(Math.random() * num);
|
|
}
|
|
|
|
/**
|
|
* 切换名牌人员信息
|
|
*/
|
|
function changeCard(cardIndex, user) {
|
|
let card = threeDCards[cardIndex].element;
|
|
// console.log("user", user);
|
|
card.innerHTML = `<div class="name">${user.jwcode}</div>`;
|
|
}
|
|
|
|
function changeSelectedCard(cardIndex, user) {
|
|
// 保存到全局变量数组
|
|
if (!globalCardIndexes.includes(cardIndex)) {
|
|
globalCardIndexes.push(cardIndex);
|
|
}
|
|
|
|
let card = threeDCards[cardIndex].element;
|
|
|
|
card.innerHTML = `<div class="name">${user.jwcode}</div>`;
|
|
}
|
|
/**
|
|
* 切换名牌背景
|
|
*/
|
|
function changeBackground(cardIndex, color) {
|
|
let card = threeDCards[cardIndex].element;
|
|
// card.style.backgroundColor =
|
|
// color || "rgba(255,170,22," + (Math.random() * 0.7 + 0.25) + ")";
|
|
card.style.backgroundColor = color || "rgba(255,170,22,1)";
|
|
card.style.border = "2px solid rgba(255, 255, 255, 1)";
|
|
}
|
|
|
|
/**
|
|
* 随机切换背景和人员信息
|
|
*/
|
|
function shineCard() {
|
|
let maxCard = 10;
|
|
let maxUser;
|
|
let shineCard = 10 + random(maxCard);
|
|
|
|
setInterval(() => {
|
|
// 正在抽奖停止闪烁
|
|
if (isLotting) {
|
|
return;
|
|
}
|
|
maxUser = users.value.length;
|
|
for (let i = 0; i < shineCard; i++) {
|
|
let index = random(maxUser);
|
|
let cardIndex = random(TOTAL_CARDS);
|
|
// 当前显示的已抽中名单不进行随机切换
|
|
if (selectedCardIndex.includes(cardIndex)) {
|
|
continue;
|
|
}
|
|
|
|
changeBackground(cardIndex);
|
|
changeCard(cardIndex, users.value[index]);
|
|
}
|
|
}, 500);
|
|
}
|
|
|
|
const createHighlight = () => {
|
|
let text = "0123";
|
|
let step = 5;
|
|
let xoffset = 1;
|
|
let yoffset = 1;
|
|
let highlight = [];
|
|
|
|
text.split("").forEach((n) => {
|
|
highlight = highlight.concat(
|
|
NUMBER_MATRIX[n].map((item) => {
|
|
return `${item[0] + xoffset}-${item[1] + yoffset}`;
|
|
})
|
|
);
|
|
xoffset += step;
|
|
});
|
|
return highlight;
|
|
};
|
|
|
|
function onWindowResize() {
|
|
camera.aspect = window.innerWidth / window.innerHeight;
|
|
camera.updateProjectionMatrix();
|
|
renderer.setSize(window.innerWidth, window.innerHeight);
|
|
render();
|
|
}
|
|
|
|
onMounted(async () => {
|
|
initAll();
|
|
|
|
window.addEventListener("resize", onWindowResize, false);
|
|
});
|
|
</script>
|
|
|
|
<style>
|
|
html,
|
|
body,
|
|
#app {
|
|
height: 100vh;
|
|
width: 100vw;
|
|
}
|
|
|
|
.homepage {
|
|
width: 100%;
|
|
height: 100%;
|
|
display: flex;
|
|
background-image: url("../../../assets/bg@2x.png");
|
|
background-repeat: no-repeat;
|
|
background-size: 100% 100%;
|
|
justify-content: center;
|
|
}
|
|
|
|
.hllogo {
|
|
position: absolute;
|
|
right: 0;
|
|
bottom: 0;
|
|
}
|
|
|
|
.qipao {
|
|
width: 100%;
|
|
z-index: 100;
|
|
position: absolute;
|
|
top: 27vh;
|
|
left: 50%;
|
|
transform: translateX(-50%);
|
|
color: #db5c58;
|
|
font-weight: bold;
|
|
font-size: 42px;
|
|
width: auto;
|
|
text-align: center;
|
|
display: none;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
a {
|
|
color: #ffffff;
|
|
}
|
|
|
|
.none {
|
|
display: none;
|
|
}
|
|
|
|
#container {
|
|
z-index: 3;
|
|
position: relative;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.three-container {
|
|
width: 100%;
|
|
height: 100%;
|
|
}
|
|
|
|
/* 分页指示器样式 */
|
|
.page-indicator {
|
|
position: absolute;
|
|
bottom: 10%;
|
|
left: 50%;
|
|
transform: translateX(-50%);
|
|
z-index: 1000;
|
|
background: rgba(0, 0, 0, 0.7);
|
|
color: white;
|
|
padding: 8px 16px;
|
|
border-radius: 20px;
|
|
font-size: 14px;
|
|
pointer-events: none;
|
|
}
|
|
|
|
.canvas-box {
|
|
/* background-color: rgb(214, 0, 0); */
|
|
position: fixed;
|
|
left: 0;
|
|
top: 0;
|
|
z-index: -1;
|
|
}
|
|
|
|
#info {
|
|
position: absolute;
|
|
width: 100%;
|
|
color: #ffffff;
|
|
padding: 5px;
|
|
font-family: Monospace;
|
|
font-size: 13px;
|
|
font-weight: bold;
|
|
text-align: center;
|
|
z-index: 1;
|
|
}
|
|
|
|
#menu {
|
|
z-index: 4;
|
|
position: absolute;
|
|
bottom: 1vh;
|
|
width: 100%;
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
}
|
|
|
|
.element {
|
|
width: 15vh;
|
|
height: 19vh;
|
|
/* box-shadow: 0 0 12px rgba(0, 255, 255, 0.5); */
|
|
border: 1px solid rgba(127, 255, 255, 0.25);
|
|
text-align: center;
|
|
cursor: default;
|
|
transition: background-color 0.3s ease-in;
|
|
}
|
|
|
|
.element:hover {
|
|
box-shadow: 0 0 12px rgba(255, 168, 38, 0.75);
|
|
border: 1px solid rgba(255, 255, 255, 1);
|
|
}
|
|
|
|
.element .name {
|
|
font-size: 2.9vh;
|
|
font-weight: bold;
|
|
color: rgba(255, 255, 255, 1);
|
|
/* text-shadow: 0 0 1vh rgba(0, 255, 255, 0.95); */
|
|
}
|
|
|
|
button {
|
|
border: none;
|
|
}
|
|
|
|
.btn {
|
|
background-image: url("../../../assets/img/抽奖按钮.png");
|
|
background-color: transparent;
|
|
background-repeat: no-repeat;
|
|
background-size: 100% 100%;
|
|
width: 180px;
|
|
height: 70px;
|
|
color: #fff;
|
|
border: 0;
|
|
font-size: 2.5vh;
|
|
font-weight: bold;
|
|
cursor: pointer;
|
|
text-align: center;
|
|
padding-top: 5px;
|
|
}
|
|
|
|
.highlight {
|
|
background: linear-gradient(360deg, #e23d26, #f49c27) !important;
|
|
box-shadow: 0 0 12px rgba(253, 105, 0, 0.95);
|
|
border: 2px solid rgba(255, 255, 255, 1);
|
|
}
|
|
|
|
.highlight.element .name {
|
|
text-shadow: 0 0 16px rgba(255, 255, 255, 0.95);
|
|
}
|
|
|
|
.prize.element .name {
|
|
text-shadow: none;
|
|
}
|
|
|
|
.prize.element {
|
|
transition: background-color 1.5s ease-in 0.3s;
|
|
background: linear-gradient(360deg, #e23d26, #f49c27) !important;
|
|
border: 2px solid rgba(255, 255, 255, 1);
|
|
}
|
|
|
|
.prize .company,
|
|
.prize .details,
|
|
.prize .name,
|
|
.highlight .company,
|
|
.highlight .name,
|
|
.highlight .details {
|
|
color: rgba(255, 255, 255, 0.85);
|
|
}
|
|
|
|
.dan-mu {
|
|
visibility: hidden;
|
|
position: fixed;
|
|
z-index: -1;
|
|
font-size: 12px;
|
|
top: 1vh;
|
|
left: 0;
|
|
padding: 0 1.2vh;
|
|
height: 2.2vh;
|
|
line-height: 2.2vh;
|
|
border-radius: 1vh;
|
|
box-sizing: border-box;
|
|
background-color: rgba(0, 127, 127, 0.37);
|
|
box-shadow: 0 0 4px rgba(0, 255, 255, 0.5);
|
|
border: 1px solid rgba(127, 255, 255, 0.25);
|
|
color: rgba(127, 255, 255, 0.75);
|
|
}
|
|
|
|
.dan-mu.active {
|
|
visibility: visible;
|
|
}
|
|
|
|
.leftBar {
|
|
position: fixed;
|
|
left: 0;
|
|
padding-left: 1.2vh;
|
|
top: 15vh;
|
|
z-index: 100;
|
|
}
|
|
|
|
#prizeBar {
|
|
max-height: 60vh;
|
|
width: 330px;
|
|
|
|
overflow-x: hidden;
|
|
overflow-y: auto;
|
|
|
|
/* 隐藏滚动条 */
|
|
scrollbar-width: none;
|
|
/* Firefox */
|
|
-ms-overflow-style: none;
|
|
/* IE */
|
|
}
|
|
|
|
#prizeBar::-webkit-scrollbar {
|
|
display: none;
|
|
/* Chrome, Safari */
|
|
}
|
|
|
|
.prize-list {
|
|
margin: 0;
|
|
padding: 0;
|
|
list-style: none;
|
|
}
|
|
|
|
.prize-item {
|
|
padding: 2px;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
flex-wrap: nowrap;
|
|
/* color: rgba(127, 255, 255, 0.75); */
|
|
width: 30vh;
|
|
height: 9.5vh;
|
|
box-sizing: border-box;
|
|
transition: transform 1s ease-in;
|
|
}
|
|
|
|
.getPrizeName {
|
|
color: #d5291f;
|
|
font-weight: bold;
|
|
font-size: 24px;
|
|
width: 27vh;
|
|
height: 5vh;
|
|
border: 2px solid rgb(255, 255, 255);
|
|
border-radius: 5px;
|
|
display: flex;
|
|
flex-direction: column;
|
|
justify-content: center;
|
|
align-items: center;
|
|
background-color: #ffd283;
|
|
opacity: 0.8;
|
|
margin-left: 2vh;
|
|
margin-top: 3.5vh;
|
|
cursor: pointer;
|
|
position: relative;
|
|
}
|
|
|
|
.dgetPrizeName {
|
|
color: #d5291f;
|
|
font-weight: bold;
|
|
font-size: 24px;
|
|
width: 27vh;
|
|
height: 60vh;
|
|
border: 2px solid rgb(255, 255, 255);
|
|
border-radius: 5px;
|
|
display: flex;
|
|
flex-direction: column;
|
|
/* justify-content: center; */
|
|
align-items: center;
|
|
background-color: #ffd283;
|
|
opacity: 0.8;
|
|
margin-left: 2vh;
|
|
margin-top: 3.5vh;
|
|
position: relative;
|
|
}
|
|
|
|
.open {
|
|
position: absolute;
|
|
top: -42px;
|
|
animation: bounce1 2s ease-in-out infinite;
|
|
transform: rotate(180deg);
|
|
}
|
|
|
|
.close {
|
|
position: absolute;
|
|
top: -32px;
|
|
animation: bounce2 2s ease-in-out infinite;
|
|
cursor: pointer;
|
|
}
|
|
|
|
@keyframes bounce1 {
|
|
0%,
|
|
100% {
|
|
transform: rotate(180deg) translateY(0);
|
|
}
|
|
|
|
50% {
|
|
transform: rotate(180deg) translateY(-8px);
|
|
}
|
|
}
|
|
|
|
@keyframes bounce2 {
|
|
0%,
|
|
100% {
|
|
transform: translateY(0);
|
|
}
|
|
|
|
50% {
|
|
transform: translateY(-8px);
|
|
}
|
|
}
|
|
|
|
.tableHead {
|
|
width: 100%;
|
|
display: flex;
|
|
justify-content: center;
|
|
font-size: 18px;
|
|
/* gap: 80px; */
|
|
margin-bottom: 10px;
|
|
position: absolute;
|
|
top: 10px;
|
|
}
|
|
|
|
.tableHead1 {
|
|
width: 50%;
|
|
text-align: center;
|
|
}
|
|
|
|
.tableHead2 {
|
|
width: 50%;
|
|
text-align: center;
|
|
}
|
|
|
|
.gradient-line {
|
|
width: 90%;
|
|
height: 3px;
|
|
border-radius: 150%;
|
|
background: linear-gradient(
|
|
to right,
|
|
transparent 0%,
|
|
#d5291f 45%,
|
|
#d5291f 55%,
|
|
transparent 100%
|
|
);
|
|
position: absolute;
|
|
bottom: -10px;
|
|
}
|
|
|
|
.tableBody {
|
|
display: flex;
|
|
margin-top: 50px;
|
|
width: 100%;
|
|
height: 50vh;
|
|
justify-content: center;
|
|
overflow-y: auto;
|
|
/* 启用垂直滚动 */
|
|
overflow-x: hidden;
|
|
/* 启用垂直滚动 */
|
|
/* 隐藏滚动条 */
|
|
scrollbar-width: none;
|
|
/* Firefox */
|
|
-ms-overflow-style: none;
|
|
/* IE */
|
|
}
|
|
|
|
.tableBody::-webkit-scrollbar {
|
|
display: none;
|
|
/* Chrome, Safari */
|
|
}
|
|
|
|
.tableItem {
|
|
display: flex;
|
|
font-size: 18px;
|
|
width: 27vh;
|
|
margin-bottom: 10px;
|
|
top: 10px;
|
|
}
|
|
|
|
.tableItem1 {
|
|
width: 50%;
|
|
text-align: center;
|
|
}
|
|
|
|
.tableItem2 {
|
|
width: 50%;
|
|
text-align: center;
|
|
}
|
|
|
|
.tableFoot {
|
|
color: #e64f39;
|
|
display: flex;
|
|
gap: 10px;
|
|
}
|
|
|
|
.leftPage {
|
|
background-color: #ccc;
|
|
color: white;
|
|
cursor: not-allowed;
|
|
/* background: linear-gradient(90deg, #ff9800 0%, #ff5722 100%); */
|
|
border-radius: 50%;
|
|
display: flex;
|
|
width: 35px;
|
|
height: 35px;
|
|
justify-content: center;
|
|
/* align-items: center; */
|
|
}
|
|
|
|
.rightPage {
|
|
color: white;
|
|
cursor: pointer;
|
|
background: linear-gradient(90deg, #ff9800 0%, #ff5722 100%);
|
|
border-radius: 50%;
|
|
display: flex;
|
|
width: 35px;
|
|
height: 35px;
|
|
justify-content: center;
|
|
}
|
|
|
|
.readyLook {
|
|
width: 100%;
|
|
height: 100%;
|
|
}
|
|
|
|
.prize-item .prize-img {
|
|
width: 7.5vh;
|
|
height: 7.5vh;
|
|
|
|
margin: auto 10px;
|
|
border-radius: 50%;
|
|
background-color: #fff;
|
|
text-shadow: 0 0 1vh rgba(0, 255, 255, 0.95);
|
|
overflow: hidden;
|
|
}
|
|
|
|
.prize-img img {
|
|
width: 90%;
|
|
height: 90%;
|
|
position: relative;
|
|
top: 50%;
|
|
left: 50%;
|
|
transform: translate(-50%, -50%);
|
|
}
|
|
|
|
.prize-text {
|
|
padding: 0 5px;
|
|
width: 100%;
|
|
height: 100%;
|
|
/* margin: auto 0; */
|
|
flex: 1;
|
|
display: flex;
|
|
flex-direction: column;
|
|
justify-content: center;
|
|
/* gap: 4px; */
|
|
}
|
|
|
|
.prize-title {
|
|
margin: 4px 0;
|
|
font-size: 1.4vh;
|
|
height: 30%;
|
|
border: 1px solid #e13726;
|
|
border-radius: 20px;
|
|
background-color: #ffffff;
|
|
display: flex;
|
|
color: #d5291f;
|
|
font-weight: bold;
|
|
display: flex;
|
|
align-items: center;
|
|
}
|
|
|
|
.level {
|
|
width: 38%;
|
|
height: 100%;
|
|
margin-right: 2%;
|
|
border-radius: 20px;
|
|
background: linear-gradient(360deg, #e23d26, #f49c27) !important;
|
|
color: #fff;
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
}
|
|
|
|
.prize-count {
|
|
padding: 4px 0;
|
|
position: relative;
|
|
}
|
|
|
|
.prize-count .progress {
|
|
height: 1.8vh;
|
|
background: rgba(0, 0, 0, 0.5);
|
|
padding: 1px;
|
|
overflow: visible;
|
|
border-radius: 1vh;
|
|
}
|
|
|
|
.progress .progress-bar {
|
|
border-radius: 1.8vh;
|
|
position: relative;
|
|
animation: animate-positive 2s;
|
|
background-color: #d9534f;
|
|
height: 1.8vh;
|
|
-webkit-transition: width 0.6s ease;
|
|
-o-transition: width 0.6s ease;
|
|
transition: width 0.6s ease;
|
|
}
|
|
|
|
.progress-bar.active {
|
|
animation: reverse progress-bar-stripes 0.4s linear infinite,
|
|
animate-positive 2s;
|
|
}
|
|
|
|
.progress-bar-striped {
|
|
background-image: -webkit-linear-gradient(
|
|
45deg,
|
|
rgba(255, 255, 255, 0.15) 25%,
|
|
transparent 25%,
|
|
transparent 50%,
|
|
rgba(255, 255, 255, 0.15) 50%,
|
|
rgba(255, 255, 255, 0.15) 75%,
|
|
transparent 75%,
|
|
transparent
|
|
);
|
|
background-image: -o-linear-gradient(
|
|
45deg,
|
|
rgba(255, 255, 255, 0.15) 25%,
|
|
transparent 25%,
|
|
transparent 50%,
|
|
rgba(255, 255, 255, 0.15) 50%,
|
|
rgba(255, 255, 255, 0.15) 75%,
|
|
transparent 75%,
|
|
transparent
|
|
);
|
|
background-image: linear-gradient(
|
|
45deg,
|
|
rgba(255, 255, 255, 0.15) 25%,
|
|
transparent 25%,
|
|
transparent 50%,
|
|
rgba(255, 255, 255, 0.15) 50%,
|
|
rgba(255, 255, 255, 0.15) 75%,
|
|
transparent 75%,
|
|
transparent
|
|
);
|
|
-webkit-background-size: 8px 8px;
|
|
background-size: 8px 8px;
|
|
}
|
|
|
|
@-webkit-keyframes animate-positive {
|
|
0% {
|
|
width: 0;
|
|
}
|
|
}
|
|
|
|
@keyframes animate-positive {
|
|
0% {
|
|
width: 0;
|
|
}
|
|
}
|
|
|
|
@-webkit-keyframes progress-bar-stripes {
|
|
from {
|
|
background-position: 8px 0;
|
|
}
|
|
|
|
to {
|
|
background-position: 0 0;
|
|
}
|
|
}
|
|
|
|
@-o-keyframes progress-bar-stripes {
|
|
from {
|
|
background-position: 8px 0;
|
|
}
|
|
|
|
to {
|
|
background-position: 0 0;
|
|
}
|
|
}
|
|
|
|
@keyframes progress-bar-stripes {
|
|
from {
|
|
background-position: 8px 0;
|
|
}
|
|
|
|
to {
|
|
background-position: 0 0;
|
|
}
|
|
}
|
|
|
|
.prize-count-left {
|
|
position: absolute;
|
|
color: #fff;
|
|
right: 35%;
|
|
font-size: 1.8vh;
|
|
line-height: 1.6vh;
|
|
top: 50%;
|
|
transform: translateY(-50%);
|
|
}
|
|
|
|
.shine {
|
|
background-color: #ffd283;
|
|
border: 1px solid rgba(255, 255, 255, 1);
|
|
border-radius: 5px;
|
|
box-shadow: 0 0 15px 0 #ffd283;
|
|
transform: scale(1.1);
|
|
transform-origin: left center;
|
|
position: relative;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.done {
|
|
position: relative;
|
|
}
|
|
|
|
.done:after {
|
|
content: "";
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
right: 0;
|
|
bottom: 0;
|
|
background-color: #ffd283;
|
|
border: 2px solid rgba(255, 255, 255, 1);
|
|
border-radius: 5px;
|
|
opacity: 0.3;
|
|
cursor: not-allowed;
|
|
}
|
|
|
|
.shine span {
|
|
position: absolute;
|
|
display: block;
|
|
}
|
|
|
|
.shine span:nth-child(1) {
|
|
top: 0;
|
|
left: 0;
|
|
width: 100%;
|
|
height: 2px;
|
|
background: linear-gradient(90deg, transparent, #f46303);
|
|
animation: animate1 1s linear infinite;
|
|
}
|
|
|
|
@keyframes animate1 {
|
|
0% {
|
|
left: -100%;
|
|
}
|
|
|
|
50%,
|
|
100% {
|
|
left: 100%;
|
|
}
|
|
}
|
|
|
|
.shine span:nth-child(2) {
|
|
top: -100%;
|
|
right: 0;
|
|
width: 2px;
|
|
height: 100%;
|
|
background: linear-gradient(180deg, transparent, #f46303);
|
|
animation: animate2 1s linear infinite;
|
|
animation-delay: 0.25s;
|
|
}
|
|
|
|
@keyframes animate2 {
|
|
0% {
|
|
top: -100%;
|
|
}
|
|
|
|
50%,
|
|
100% {
|
|
top: 100%;
|
|
}
|
|
}
|
|
|
|
.shine span:nth-child(3) {
|
|
bottom: 0;
|
|
right: 0;
|
|
width: 100%;
|
|
height: 2px;
|
|
background: linear-gradient(270deg, transparent, #f46303);
|
|
animation: animate3 1s linear infinite;
|
|
animation-delay: 0.5s;
|
|
}
|
|
|
|
@keyframes animate3 {
|
|
0% {
|
|
right: -100%;
|
|
}
|
|
|
|
50%,
|
|
100% {
|
|
right: 100%;
|
|
}
|
|
}
|
|
|
|
.shine span:nth-child(4) {
|
|
bottom: -100%;
|
|
left: 0;
|
|
width: 2px;
|
|
height: 100%;
|
|
background: linear-gradient(360deg, transparent, #f46303);
|
|
animation: animate4 1s linear infinite;
|
|
animation-delay: 0.75s;
|
|
}
|
|
|
|
@keyframes animate4 {
|
|
0% {
|
|
bottom: -100%;
|
|
}
|
|
|
|
50%,
|
|
100% {
|
|
bottom: 100%;
|
|
}
|
|
}
|
|
|
|
.shine.prize-item {
|
|
/* width: 24vh; */
|
|
margin: 1.2vh 0;
|
|
}
|
|
|
|
.prize-mess {
|
|
color: #fff;
|
|
line-height: 5vh;
|
|
font-size: 1.6vh;
|
|
margin: 2.4vh 0;
|
|
}
|
|
|
|
.music {
|
|
position: fixed;
|
|
top: 3vh;
|
|
right: 4vh;
|
|
z-index: 5;
|
|
}
|
|
|
|
.music-item {
|
|
display: block !important;
|
|
opacity: 0;
|
|
}
|
|
|
|
.music-box {
|
|
width: 5vh;
|
|
height: 5vh;
|
|
border-radius: 50%;
|
|
text-align: center;
|
|
line-height: 5vh;
|
|
font-size: 1.4vh;
|
|
color: #fff;
|
|
cursor: pointer;
|
|
background-color: rgba(253, 105, 0, 0.9);
|
|
border: 1px solid rgba(255, 255, 255, 0.5);
|
|
}
|
|
|
|
.rotate-active {
|
|
animation: rotate 4s linear infinite;
|
|
}
|
|
|
|
@keyframes rotate {
|
|
from {
|
|
transform: rotate(0);
|
|
}
|
|
|
|
to {
|
|
transform: rotate(360deg);
|
|
}
|
|
}
|
|
|
|
.margin-l-40 {
|
|
margin-left: 40px;
|
|
}
|
|
|
|
.fixed-bar {
|
|
position: fixed;
|
|
bottom: 20px;
|
|
right: 20px;
|
|
}
|
|
|
|
.fixed-btn {
|
|
margin: 20px 0 0;
|
|
width: 200px;
|
|
text-align: center;
|
|
display: block;
|
|
}
|
|
|
|
#lottery {
|
|
animation: breath 1.6s linear infinite;
|
|
/* box-shadow: 0px 0px 15px rgb(127 255 255 / 75%); */
|
|
}
|
|
|
|
@keyframes breath {
|
|
0% {
|
|
transform: scale(1);
|
|
opacity: 0.8;
|
|
}
|
|
|
|
25% {
|
|
transform: scale(1.1);
|
|
opacity: 1;
|
|
}
|
|
|
|
50% {
|
|
transform: scale(1);
|
|
opacity: 1;
|
|
}
|
|
|
|
75% {
|
|
transform: scale(0.9);
|
|
opacity: 1;
|
|
}
|
|
|
|
100% {
|
|
transform: scale(1);
|
|
opacity: 0.8;
|
|
}
|
|
}
|
|
</style>
|