123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397 |
- <template>
- <page-layer>
- <template #aside>
- <div style="width: 300px;height: 100%;
- background-size: 100% 100%;
- background-repeat: no-repeat;
- background-image: url('http://webhis.thyy.cn:8080/resource/image/happyAside.jpg')">
- <div style="height: 1px"></div>
- <div style="background-color: rgba(255,255,255,0.7); margin: 16px; padding: 2px; border-radius: 8px">
- <div style="margin: 12px 0 12px 10px; font-size: 18px; color: #014841; font-weight: bold">
- 奖项设置
- <span class="reset-pool" @click="initLotteryPool">重置为初始状态</span>
- </div>
- <div style="margin-left: 12px">
- <div v-for="item in lotteryPool" :key="item.code">
- <div style="display: flex; line-height: 32px; font-size: 16px">
- <div style="width: 65px; color: black; font-weight: bold">{{ item.name }}:</div>
- <div style="width: 40px; color: #007bd9; font-weight: bold">{{ item.amount }} 份</div>
- <div style="width: calc(100% - 120px); text-align: right">
- <el-button circle icon="Edit" @click="editRule(item)"></el-button>
- <el-checkbox v-model="item.showWinner" @change="refreshHistory"
- style="margin-left: 8px">名单</el-checkbox>
- </div>
- </div>
- </div>
- </div>
- </div>
- <div style="width: 300px; text-align: center; margin-top: 20px">
- <div style="color: white;text-align: left;padding-left: 50px;margin-bottom: 12px">
- <el-checkbox v-model="continuous">连续抽奖</el-checkbox>
- </div>
- <el-button style="width: 200px" size="large" :disabled="duringLottery"
- type="danger" icon="Star" @click="startLottery">开始抽奖
- </el-button>
- <el-scrollbar ref="wonUserRef" height="510px" style="margin-top: 20px">
- <div v-for="user in historyWonUsers" style="line-height: 30px; font-size: 16px">
- <span style="color: white">{{user.codeRs}} - {{user.name}}:</span>
- <span style="color: white; font-weight: bold">{{user.wonName}}</span>
- </div>
- </el-scrollbar>
- </div>
- </div>
- </template>
- <template #main>
- <div style="position:relative;width: 100%; height: 100%;
- overflow-y: hidden;
- background-size: 100% 100%;
- background-repeat: no-repeat;
- background-image: url('http://webhis.thyy.cn:8080/resource/image/happyNewYear.jpg')">
- <div style="height: 19%;width: 100%;display: flex;align-items: end;
- justify-content: center;color: white;font-size: 56px;font-weight: bold">
- 当前奖项:{{ currentLotteryName }}
- </div>
- <div style="height: 60%; width: 100%; display: flex;align-items: center;
- justify-content: center;color: white;font-size: 152px;font-weight: bold">
- <span id="winner-div">{{ currentUserName }}</span>
- </div>
- <div style="position: absolute; top:0;right:0;bottom: 0">
- <canvas id="canvas"></canvas>
- </div>
- </div>
- </template>
- </page-layer>
- </template>
- <script setup>
- import PageLayer from "@/layout/PageLayer.vue";
- import {ElMessageBox} from "element-plus";
- import {selectLotteryUsers, chooseWinner, recordLotteryResult, selectWonUsers} from "@/api/single-page/lottery";
- const continuous = ref(false)
- const lotteryPool = ref([])
- const lotteryUsers = ref([])
- const duringLottery = ref(false)
- const winner = reactive({
- index: -1,
- lotteryCode: '',
- userCodeRs: '',
- userName: ''
- })
- const currentLotteryName = ref('三等奖')
- const currentUserName = ref('等待抽奖')
- function initLotteryPool() {
- lotteryPool.value = [
- {code: 0, name: '特等奖', amount: 0, round: 0, showWinner: false},
- {code: 1, name: '一等奖', amount: 0, round: 0, showWinner: false},
- {code: 2, name: '二等奖', amount: 0, round: 0, showWinner: false},
- {code: 3, name: '三等奖', amount: 0, round: 0, showWinner: false},
- ]
- localStorage.setItem('lotteryPool', JSON.stringify(lotteryPool.value))
- }
- let carouselInterval = null
- function moveToWinner() {
- let offset = continuous.value ? 1000 : 4500;
- let timer = 0;
- carouselInterval = setInterval(() => {
- timer += 100
- if (timer >= offset) {
- winnerExposed()
- return
- }
- let index = Math.floor(Math.random() * lotteryUsers.value.length);
- let tempUser = lotteryUsers.value[index]
- currentUserName.value = tempUser.codeRs + ' - ' + tempUser.name
- if (tempUser.codeRs === winner.userCodeRs && timer >= offset) {
- winnerExposed()
- }
- }, 100)
- }
- function winnerExposed() {
- recordLotteryResult(winner).then(() => {
- currentUserName.value = winner.userCodeRs + ' - ' + winner.userName
- duringLottery.value = false;
- clearInterval(carouselInterval)
- refreshHistory()
- startFirework()
- const element = document.getElementById('winner-div')
- element.style.transitionDuration = '.5s'
- element.style.transitionTimingFunction = 'ease-in-out'
- element.style.transformOrigin = 'center center'
- element.style.transform = `scale(1.3, 1.3)`;
- // 完成后重置样式
- setTimeout(() => {
- element.style.removeProperty('transition-duration');
- element.style.removeProperty('transition-timing-function');
- element.style.removeProperty('transform-origin');
- element.style.removeProperty('transform');
- if (continuous.value) {
- setTimeout(() => {
- startLottery()
- }, 400);
- }
- }, 600);
- })
- }
- function startLottery() {
- duringLottery.value = true
- getWinnableLottery().then(item => {
- chooseWinner(item).then(res => {
- winner.lotteryCode = item.code
- winner.userCodeRs = res.codeRs
- winner.userName = res.name
- moveToWinner()
- })
- }).catch(() => {
- duringLottery.value = false
- })
- }
- function getWinnableLottery() {
- return new Promise((resolve, reject) => {
- for (let i = lotteryPool.value.length - 1; i >= 0; i--) {
- const item = lotteryPool.value[i]
- if (item.amount === 1) {
- continuous.value = false
- }
- if (item.amount > 0) {
- item.amount -= 1
- item.round += 1
- item.showWinner = true
- currentLotteryName.value = item.name
- localStorage.setItem('lotteryPool', JSON.stringify(lotteryPool.value))
- resolve(item)
- return
- } else {
- item.showWinner = false
- }
- }
- reject()
- })
- }
- function editRule(item) {
- ElMessageBox.prompt(`设置${item.name}数量:`, '提示', {
- type: "warning",
- confirmButtonText: '确定',
- cancelButtonText: '取消',
- inputPattern: /^100$|^(\d|[1-9]\d)$/,
- inputErrorMessage: '请输入 0至100 的整数',
- }).then(({value}) => {
- item.amount = Number.parseInt(value)
- localStorage.setItem('lotteryPool', JSON.stringify(lotteryPool.value))
- })
- }
- const historyWonUsers = ref([])
- function refreshHistory () {
- const params = []
- lotteryPool.value.forEach(item => {
- if (item.showWinner) {
- params.push(item.code)
- }
- })
- selectWonUsers(params).then(res => {
- historyWonUsers.value = res
- if (res.length > 17) {
- scrollIfExceedLength(res.length - 17)
- }
- })
- }
- const wonUserRef = ref(null)
- let scrollInterval = null
- let target = 0;
- function scrollIfExceedLength(len) {
- let height = len * 30;
- clearInterval(scrollInterval)
- nextTick(() => {
- const wrap = wonUserRef.value.wrapRef;
- scrollInterval = setInterval(() => {
- target += 1
- if (target > (height + 15)) {
- target = -1
- } else {
- wrap.scrollTop = target
- }
- }, 50)
- })
- }
- onDeactivated(() => {
- clearInterval(scrollInterval)
- })
- onMounted(() => {
- let storage = localStorage.getItem('lotteryPool')
- if (storage) {
- lotteryPool.value = JSON.parse(storage);
- } else {
- initLotteryPool()
- }
- selectLotteryUsers().then(res => {
- lotteryUsers.value = res
- initFireworkCanvas()
- refreshHistory()
- })
- })
- let canvas, canvasContext, w, h, particles = [], probability = 0.04,
- xPoint, yPoint;
- const fireworkRunnable = ref(false)
- function initFireworkCanvas() {
- canvas = document.getElementById("canvas");
- canvasContext = canvas.getContext("2d");
- resizeCanvas();
- }
- function resizeCanvas() {
- if (canvas) {
- w = canvas.width = window.innerWidth;
- h = canvas.height = window.innerHeight;
- }
- }
- function startFirework() {
- fireworkRunnable.value = true
- window.requestAnimationFrame(updateWorld);
- setTimeout(() => {
- fireworkRunnable.value = false
- canvasContext.clearRect(0, 0, canvas.width, canvas.height);
- }, 4000)
- }
- function updateWorld() {
- if (fireworkRunnable.value) {
- update();
- paint();
- window.requestAnimationFrame(updateWorld);
- }
- }
- function update() {
- if (particles.length < 500 && Math.random() < probability) {
- createFirework();
- }
- let alive = [];
- for (let i = 0; i < particles.length; i++) {
- if (particles[i].move()) {
- alive.push(particles[i]);
- }
- }
- particles = alive;
- canvasContext.clearRect(0, 0, canvas.width, canvas.height);
- }
- function paint() {
- canvasContext.globalCompositeOperation = 'source-over';
- canvasContext.fillStyle = "transparent";
- canvasContext.fillRect(0, 0, w, h);
- canvasContext.globalCompositeOperation = 'lighter';
- for (let i = 0; i < particles.length; i++) {
- particles[i].draw(canvasContext);
- }
- }
- function createFirework() {
- xPoint = Math.random() * (w - 200) + 100;
- yPoint = Math.random() * (h - 200) + 100;
- let nFire = Math.floor(Math.random() * 100) + 100;
- let c1 = 'rgb(255,' + Math.floor((Math.random() * 255)) + ',' + Math.floor((Math.random() * 255)) + ')';
- let c2 = 'rgb(' + Math.floor((Math.random() * 255)) + ',255,' + Math.floor((Math.random() * 255)) + ')';
- let c3 = 'rgb(' + Math.floor((Math.random() * 255)) + ',' + Math.floor((Math.random() * 255)) + ',255)';
- let c=[c1,c2,c3]
- for (let i = 0; i < nFire; i++) {
- let particle = new Particle();
- particle.color = c[Math.floor(Math.random() * 3)];
- let vy = Math.sqrt(25 - particle.vx * particle.vx);
- if (Math.abs(particle.vy) > vy) {
- particle.vy = particle.vy > 0 ? vy : -vy;
- }
- particles.push(particle);
- }
- }
- function Particle() {
- this.w = this.h = Math.random() * 6 + 1;
- this.x = xPoint - this.w / 2;
- this.y = yPoint - this.h / 2;
- this.vx = (Math.random() - 0.5) * 10;
- this.vy = (Math.random() - 0.5) * 10;
- this.alpha = Math.random() * .5 + .5;
- this.color = '';
- }
- Particle.prototype = {
- gravity: 0.05,
- move: function () {
- this.x += this.vx;
- this.vy += this.gravity;
- this.y += this.vy;
- this.alpha -= 0.01;
- return !(this.x <= -this.w || this.x >= screen.width ||
- this.y >= screen.height ||
- this.alpha <= 0);
- },
- draw: function (c) {
- c.save();
- c.beginPath();
- c.translate(this.x + this.w / 2, this.y + this.h / 2);
- c.arc(0, 0, this.w, 0, Math.PI * 2);
- c.fillStyle = this.color;
- c.globalAlpha = this.alpha;
- c.closePath();
- c.fill();
- c.restore();
- }
- }
- </script>
- <style scoped>
- :deep(.el-upload-dragger) {
- background-color: transparent;
- }
- .reset-pool {
- color: red;
- font-size: 12px
- }
- .reset-pool:hover {
- cursor: pointer;
- text-decoration: underline;
- }
- .show-history {
- color: #c2c2c2;
- }
- .show-history:hover {
- cursor: pointer;
- text-decoration: underline;
- }
- :deep(.el-checkbox) {
- color: white;
- }
- </style>
|