feat(home): 重构抽奖逻辑并优化初始化流程 Feature #91
This commit is contained in:
25
pnpm-lock.yaml
generated
25
pnpm-lock.yaml
generated
@@ -1392,36 +1392,42 @@ packages:
|
||||
engines: {node: '>= 10.0.0'}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@parcel/watcher-linux-arm-musl@2.5.0':
|
||||
resolution: {integrity: sha512-6uHywSIzz8+vi2lAzFeltnYbdHsDm3iIB57d4g5oaB9vKwjb6N6dRIgZMujw4nm5r6v9/BQH0noq6DzHrqr2pA==}
|
||||
engines: {node: '>= 10.0.0'}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@parcel/watcher-linux-arm64-glibc@2.5.0':
|
||||
resolution: {integrity: sha512-BfNjXwZKxBy4WibDb/LDCriWSKLz+jJRL3cM/DllnHH5QUyoiUNEp3GmL80ZqxeumoADfCCP19+qiYiC8gUBjA==}
|
||||
engines: {node: '>= 10.0.0'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@parcel/watcher-linux-arm64-musl@2.5.0':
|
||||
resolution: {integrity: sha512-S1qARKOphxfiBEkwLUbHjCY9BWPdWnW9j7f7Hb2jPplu8UZ3nes7zpPOW9bkLbHRvWM0WDTsjdOTUgW0xLBN1Q==}
|
||||
engines: {node: '>= 10.0.0'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@parcel/watcher-linux-x64-glibc@2.5.0':
|
||||
resolution: {integrity: sha512-d9AOkusyXARkFD66S6zlGXyzx5RvY+chTP9Jp0ypSTC9d4lzyRs9ovGf/80VCxjKddcUvnsGwCHWuF2EoPgWjw==}
|
||||
engines: {node: '>= 10.0.0'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@parcel/watcher-linux-x64-musl@2.5.0':
|
||||
resolution: {integrity: sha512-iqOC+GoTDoFyk/VYSFHwjHhYrk8bljW6zOhPuhi5t9ulqiYq1togGJB5e3PwYVFFfeVgc6pbz3JdQyDoBszVaA==}
|
||||
engines: {node: '>= 10.0.0'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@parcel/watcher-win32-arm64@2.5.0':
|
||||
resolution: {integrity: sha512-twtft1d+JRNkM5YbmexfcH/N4znDtjgysFaV9zvZmmJezQsKpkfLYJ+JFV3uygugK6AtIM2oADPkB2AdhBrNig==}
|
||||
@@ -1492,56 +1498,67 @@ packages:
|
||||
resolution: {integrity: sha512-aL6hRwu0k7MTUESgkg7QHY6CoqPgr6gdQXRJI1/VbFlUMwsSzPGSR7sG5d+MCbYnJmJwThc2ol3nixj1fvI/zQ==}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-arm-musleabihf@4.52.0':
|
||||
resolution: {integrity: sha512-BTs0M5s1EJejgIBJhCeiFo7GZZ2IXWkFGcyZhxX4+8usnIo5Mti57108vjXFIQmmJaRyDwmV59Tw64Ap1dkwMw==}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rollup/rollup-linux-arm64-gnu@4.52.0':
|
||||
resolution: {integrity: sha512-uj672IVOU9m08DBGvoPKPi/J8jlVgjh12C9GmjjBxCTQc3XtVmRkRKyeHSmIKQpvJ7fIm1EJieBUcnGSzDVFyw==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-arm64-musl@4.52.0':
|
||||
resolution: {integrity: sha512-/+IVbeDMDCtB/HP/wiWsSzduD10SEGzIZX2945KSgZRNi4TSkjHqRJtNTVtVb8IRwhJ65ssI56krlLik+zFWkw==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rollup/rollup-linux-loong64-gnu@4.52.0':
|
||||
resolution: {integrity: sha512-U1vVzvSWtSMWKKrGoROPBXMh3Vwn93TA9V35PldokHGqiUbF6erSzox/5qrSMKp6SzakvyjcPiVF8yB1xKr9Pg==}
|
||||
cpu: [loong64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-ppc64-gnu@4.52.0':
|
||||
resolution: {integrity: sha512-X/4WfuBAdQRH8cK3DYl8zC00XEE6aM472W+QCycpQJeLWVnHfkv7RyBFVaTqNUMsTgIX8ihMjCvFF9OUgeABzw==}
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-riscv64-gnu@4.52.0':
|
||||
resolution: {integrity: sha512-xIRYc58HfWDBZoLmWfWXg2Sq8VCa2iJ32B7mqfWnkx5mekekl0tMe7FHpY8I72RXEcUkaWawRvl3qA55og+cwQ==}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-riscv64-musl@4.52.0':
|
||||
resolution: {integrity: sha512-mbsoUey05WJIOz8U1WzNdf+6UMYGwE3fZZnQqsM22FZ3wh1N887HT6jAOjXs6CNEK3Ntu2OBsyQDXfIjouI4dw==}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rollup/rollup-linux-s390x-gnu@4.52.0':
|
||||
resolution: {integrity: sha512-qP6aP970bucEi5KKKR4AuPFd8aTx9EF6BvutvYxmZuWLJHmnq4LvBfp0U+yFDMGwJ+AIJEH5sIP+SNypauMWzg==}
|
||||
cpu: [s390x]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-x64-gnu@4.52.0':
|
||||
resolution: {integrity: sha512-nmSVN+F2i1yKZ7rJNKO3G7ZzmxJgoQBQZ/6c4MuS553Grmr7WqR7LLDcYG53Z2m9409z3JLt4sCOhLdbKQ3HmA==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-x64-musl@4.52.0':
|
||||
resolution: {integrity: sha512-2d0qRo33G6TfQVjaMR71P+yJVGODrt5V6+T0BDYH4EMfGgdC/2HWDVjSSFw888GSzAZUwuska3+zxNUCDco6rQ==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rollup/rollup-openharmony-arm64@4.52.0':
|
||||
resolution: {integrity: sha512-A1JalX4MOaFAAyGgpO7XP5khquv/7xKzLIyLmhNrbiCxWpMlnsTYr8dnsWM7sEeotNmxvSOEL7F65j0HXFcFsw==}
|
||||
@@ -1623,24 +1640,28 @@ packages:
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@tailwindcss/oxide-linux-arm64-musl@4.1.13':
|
||||
resolution: {integrity: sha512-hZQrmtLdhyqzXHB7mkXfq0IYbxegaqTmfa1p9MBj72WPoDD3oNOh1Lnxf6xZLY9C3OV6qiCYkO1i/LrzEdW2mg==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@tailwindcss/oxide-linux-x64-gnu@4.1.13':
|
||||
resolution: {integrity: sha512-uaZTYWxSXyMWDJZNY1Ul7XkJTCBRFZ5Fo6wtjrgBKzZLoJNrG+WderJwAjPzuNZOnmdrVg260DKwXCFtJ/hWRQ==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@tailwindcss/oxide-linux-x64-musl@4.1.13':
|
||||
resolution: {integrity: sha512-oXiPj5mi4Hdn50v5RdnuuIms0PVPI/EG4fxAfFiIKQh5TgQgX7oSuDWntHW7WNIi/yVLAiS+CRGW4RkoGSSgVQ==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@tailwindcss/oxide-wasm32-wasi@4.1.13':
|
||||
resolution: {integrity: sha512-+LC2nNtPovtrDwBc/nqnIKYh/W2+R69FA0hgoeOn64BdCX522u19ryLh3Vf3F8W49XBcMIxSe665kwy21FkhvA==}
|
||||
@@ -3854,24 +3875,28 @@ packages:
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
lightningcss-linux-arm64-musl@1.30.1:
|
||||
resolution: {integrity: sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
lightningcss-linux-x64-gnu@1.30.1:
|
||||
resolution: {integrity: sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
lightningcss-linux-x64-musl@1.30.1:
|
||||
resolution: {integrity: sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
lightningcss-win32-arm64-msvc@1.30.1:
|
||||
resolution: {integrity: sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA==}
|
||||
|
||||
@@ -14,7 +14,7 @@ import useStore from '@/store'
|
||||
import { selectCard } from '@/utils'
|
||||
import { rgba } from '@/utils/color'
|
||||
import { LotteryStatus } from './type'
|
||||
import { confettiFire, createSphereVertices, createTableVertices, initTableData } from './util'
|
||||
import { confettiFire, createSphereVertices, createTableVertices, getRandomElements, initTableData } from './utils'
|
||||
|
||||
export function useViewModel() {
|
||||
const toast = useToast()
|
||||
@@ -52,7 +52,7 @@ export function useViewModel() {
|
||||
const personPool = ref<IPersonConfig[]>([])
|
||||
const intervalTimer = ref<any>(null)
|
||||
|
||||
function init() {
|
||||
function initThreeJs() {
|
||||
const felidView = 40
|
||||
const width = window.innerWidth
|
||||
const height = window.innerHeight
|
||||
@@ -358,14 +358,22 @@ export function useViewModel() {
|
||||
}
|
||||
}
|
||||
luckyCount.value = leftover < luckyCount.value ? leftover : luckyCount.value
|
||||
for (let i = 0; i < luckyCount.value; i++) {
|
||||
if (personPool.value.length > 0) {
|
||||
// 解决随机元素概率过于不均等问题
|
||||
const randomIndex = Math.floor(Math.random() * (personPool.value.length - 1))
|
||||
luckyTargets.value.push(personPool.value[randomIndex])
|
||||
personPool.value.splice(randomIndex, 1)
|
||||
}
|
||||
// 重构抽奖函数
|
||||
luckyTargets.value = getRandomElements(personPool.value, luckyCount.value)
|
||||
luckyTargets.value.forEach((item) => {
|
||||
const index = personPool.value.findIndex(person => person.id === item.id)
|
||||
if (index > -1) {
|
||||
personPool.value.splice(index, 1)
|
||||
}
|
||||
})
|
||||
// for (let i = 0; i < luckyCount.value; i++) {
|
||||
// if (personPool.value.length > 0) {
|
||||
// // 解决随机元素概率过于不均等问题
|
||||
// const randomIndex = Math.floor(Math.random() * (personPool.value.length - 1))
|
||||
// luckyTargets.value.push(personPool.value[randomIndex])
|
||||
// personPool.value.splice(randomIndex, 1)
|
||||
// }
|
||||
// }
|
||||
|
||||
toast.open({
|
||||
// message: `现在抽取${currentPrize.value.name} ${leftover}人`,
|
||||
@@ -575,13 +583,32 @@ export function useViewModel() {
|
||||
// 刷新页面
|
||||
window.location.reload()
|
||||
}
|
||||
onMounted(() => {
|
||||
const init = () => {
|
||||
const startTime = Date.now()
|
||||
const maxWaitTime = 2000 // 2秒
|
||||
|
||||
const checkAndInit = () => {
|
||||
// 如果人员列表有数据或者等待时间超过2秒,则执行初始化
|
||||
if (allPersonList.value.length > 0 || (Date.now() - startTime) >= maxWaitTime) {
|
||||
console.log('初始化完成')
|
||||
tableData.value = initTableData({ allPersonList: allPersonList.value, rowCount: rowCount.value })
|
||||
init()
|
||||
initThreeJs()
|
||||
animation()
|
||||
containerRef.value!.style.color = `${textColor}`
|
||||
randomBallData()
|
||||
window.addEventListener('keydown', listenKeyboard)
|
||||
}
|
||||
else {
|
||||
console.log('等待人员列表数据...')
|
||||
// 继续等待
|
||||
setTimeout(checkAndInit, 100) // 每100毫秒检查一次
|
||||
}
|
||||
}
|
||||
|
||||
checkAndInit()
|
||||
}
|
||||
onMounted(() => {
|
||||
init()
|
||||
})
|
||||
onUnmounted(() => {
|
||||
nextTick(() => {
|
||||
@@ -591,6 +618,11 @@ export function useViewModel() {
|
||||
intervalTimer.value = null
|
||||
window.removeEventListener('keydown', listenKeyboard)
|
||||
})
|
||||
// watch(() => allPersonList.value, (newVal) => {
|
||||
// if (newVal.length) {
|
||||
// init()
|
||||
// }
|
||||
// })
|
||||
|
||||
return {
|
||||
setDefaultPersonList,
|
||||
|
||||
2
src/views/Home/utils/index.ts
Normal file
2
src/views/Home/utils/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export * from './random'
|
||||
export * from './table'
|
||||
131
src/views/Home/utils/table.ts
Normal file
131
src/views/Home/utils/table.ts
Normal 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),
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user