diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index bd00353..b7bd84d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -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==} diff --git a/src/views/Home/useViewModel.ts b/src/views/Home/useViewModel.ts index cebfdf3..e3e879e 100644 --- a/src/views/Home/useViewModel.ts +++ b/src/views/Home/useViewModel.ts @@ -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([]) const intervalTimer = ref(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() } + 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 }) + initThreeJs() + animation() + containerRef.value!.style.color = `${textColor}` + randomBallData() + window.addEventListener('keydown', listenKeyboard) + } + else { + console.log('等待人员列表数据...') + // 继续等待 + setTimeout(checkAndInit, 100) // 每100毫秒检查一次 + } + } + + checkAndInit() + } onMounted(() => { - tableData.value = initTableData({ allPersonList: allPersonList.value, rowCount: rowCount.value }) init() - animation() - containerRef.value!.style.color = `${textColor}` - randomBallData() - window.addEventListener('keydown', listenKeyboard) }) 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, diff --git a/src/views/Home/utils/index.ts b/src/views/Home/utils/index.ts new file mode 100644 index 0000000..4f2e586 --- /dev/null +++ b/src/views/Home/utils/index.ts @@ -0,0 +1,2 @@ +export * from './random' +export * from './table' diff --git a/src/views/Home/utils/table.ts b/src/views/Home/utils/table.ts new file mode 100644 index 0000000..1c3cea1 --- /dev/null +++ b/src/views/Home/utils/table.ts @@ -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), + }) +}