feat: pattern config

This commit is contained in:
ex_zhangwenlei@exiot.cmcc
2024-01-11 23:53:53 +08:00
parent 53af03648e
commit 2ba3bb036b
18 changed files with 621 additions and 147 deletions

View File

@@ -1,5 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import { onMounted } from 'vue' import { onMounted,ref } from 'vue'
import useStore from '@/store' import useStore from '@/store'
import { storeToRefs } from 'pinia' import { storeToRefs } from 'pinia'
import PlayMusic from '@/components/PlayMusic/index.vue' import PlayMusic from '@/components/PlayMusic/index.vue'
@@ -8,8 +8,13 @@ import { themeChange } from 'theme-change'
const globalConfig = useStore().globalConfig const globalConfig = useStore().globalConfig
const prizeConfig = useStore().prizeConfig const prizeConfig = useStore().prizeConfig
const system=useStore().system
const { getTheme: localTheme } = storeToRefs(globalConfig) const { getTheme: localTheme } = storeToRefs(globalConfig)
const { getPrizeConfig: prizeList } = storeToRefs(prizeConfig) const { getPrizeConfig: prizeList } = storeToRefs(prizeConfig)
// const { getIsMobile: isMobile } = storeToRefs(system)
const tipDialog=ref()
// const isMobileValue = ref(structuredClone(isMobile.value))
const setLocalTheme = (theme: any) => { const setLocalTheme = (theme: any) => {
themeChange(theme.name) themeChange(theme.name)
} }
@@ -29,13 +34,37 @@ const setCurrentPrize = () => {
return return
} }
// 判断是否手机端访问
const judgeMobile=()=>{
const ua = navigator.userAgent
const isAndroid = ua.indexOf('Android') > -1 || ua.indexOf('Adr') > -1
const isIOS =!!ua.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/)
if(isAndroid||isIOS){
tipDialog.value.showModal()
}
system.setIsMobile(isAndroid||isIOS)
}
onMounted(() => { onMounted(() => {
setLocalTheme(localTheme.value) setLocalTheme(localTheme.value)
setCurrentPrize() setCurrentPrize()
judgeMobile()
}) })
</script> </script>
<template> <template>
<dialog id="my_modal_1" ref="tipDialog" class="border-none modal">
<div class="modal-box">
<h3 class="text-lg font-bold">提示!</h3>
<p class="py-4">请使用PC进行访问以获得最佳显示效果</p>
<div class="modal-action">
<form method="dialog" class="flex gap-3 justify-start w-full">
<!-- if there is a button in form, it will close the modal -->
<button class="btn">确定</button>
</form>
</div>
</div>
</dialog>
<router-view></router-view> <router-view></router-view>
<PlayMusic class="absolute right-0 bottom-1/2"></PlayMusic> <PlayMusic class="absolute right-0 bottom-1/2"></PlayMusic>
</template> </template>

View File

@@ -1,54 +1,91 @@
import { rgba } from '@/utils/color' import { rgba } from '@/utils/color'
import { IPersonConfig } from '@/types/storeType'
export const useElementStyle=(element:any,cardColor:string,cardSize:{width:number,height:number},textSize:number,mod:'default'|'lucky'='default')=>{ export const useElementStyle = (element: any, person: IPersonConfig, index: number, patternList: number[], patternColor: string, cardColor: string, cardSize: { width: number, height: number }, textSize: number, mod: 'default' | 'lucky'|'sphere' = 'default') => {
element.style.backgroundColor = rgba(cardColor, mod=='default'?Math.random() * 0.5 + 0.25:0.8) if (patternList.includes(index+1)&&mod=='default') {
element.style.backgroundColor = rgba(patternColor, Math.random() * 0.5 + 0.5)
}
else if(mod=='sphere'||mod=='default') {
element.style.backgroundColor = rgba(cardColor, Math.random() * 0.5 + 0.25)
}
else if(mod=='lucky'){
element.style.backgroundColor = rgba(cardColor, 0.8)
}
element.style.border = `1px solid ${rgba(cardColor, 0.25)}` element.style.border = `1px solid ${rgba(cardColor, 0.25)}`
element.style.boxShadow = `0 0 12px ${rgba(cardColor, 0.5)}` element.style.boxShadow = `0 0 12px ${rgba(cardColor, 0.5)}`
element.style.width = `${cardSize.width}px`; element.style.width = `${cardSize.width}px`;
element.style.height = `${cardSize.height}px`; element.style.height = `${cardSize.height}px`;
if (mod == 'lucky') {
element.className = 'lucky-element-card'
}
else {
element.className = 'element-card'
}
// 等比放大 // 等比放大
element.addEventListener('mouseenter', (ev: MouseEvent) => {
element.addEventListener('mouseenter', (ev:MouseEvent)=> {
// 子元素无效
// ev.stopPropagation()
// ev.preventDefault()
const target = ev.target as HTMLElement const target = ev.target as HTMLElement
target.style.border = `1px solid ${rgba(cardColor, 0.75)}` target.style.border = `1px solid ${rgba(cardColor, 0.75)}`
target.style.boxShadow = `0 0 12px ${rgba(cardColor, 0.75)}` target.style.boxShadow = `0 0 12px ${rgba(cardColor, 0.75)}`
}) })
element.addEventListener('mouseleave', (ev:MouseEvent)=>{ element.addEventListener('mouseleave', (ev: MouseEvent) => {
// ev.stopPropagation() const target = ev.target as HTMLElement
// ev.preventDefault()
const target=ev.target as HTMLElement
target.style.border = `1px solid ${rgba(cardColor, 0.25)}` target.style.border = `1px solid ${rgba(cardColor, 0.25)}`
target.style.boxShadow = `0 0 12px ${rgba(cardColor, 0.5)}` target.style.boxShadow = `0 0 12px ${rgba(cardColor, 0.5)}`
}) })
element.children[0].style.fontSize = textSize*0.5+'px' element.children[0].style.fontSize = textSize * 0.5 + 'px';
if (person.uid) {
element.children[0].textContent = person.uid;
}
element.children[1].style.fontSize = textSize+'px' element.children[1].style.fontSize = textSize + 'px'
element.children[1].style.lineHeight = textSize*3+'px' element.children[1].style.lineHeight = textSize * 3 + 'px'
element.children[1].style.textShadow = `0 0 12px ${rgba(cardColor, 0.95)}` element.children[1].style.textShadow = `0 0 12px ${rgba(cardColor, 0.95)}`
if (person.name) {
element.children[1].textContent = person.name
}
element.children[2].style.fontSize = textSize*0.5+'px' element.children[2].style.fontSize = textSize * 0.5 + 'px'
if (person.department || person.identity) {
element.children[2].innerHTML = `${person.department ? person.department : ''}<br/>${person.identity ? person.identity : ''}`
}
return element return element
} }
export const useElementPosition=(element:any,count:number,cardSize:{width:number,height:number},windowSize:{width:number,height:number},cardIndex:number)=>{ // export const useElementPosition=(element:any,count:number,cardSize:{width:number,height:number},windowSize:{width:number,height:number},cardIndex:number)=>{
const centerPosition={ // const centerPosition={
x:0, // x:0,
y:windowSize.height/2-cardSize.height/2 // y:windowSize.height/2-cardSize.height/2
// }
// const index =cardIndex%5
// if(index==0){
// element.position.x=centerPosition.x
// element.position.y=centerPosition.y-Math.floor(cardIndex/5)*(cardSize.height+60)
// }
// else{
// element.position.x=index%2===0?Math.ceil(index/2)*(cardSize.width+100):-Math.ceil(index/2)*(cardSize.width+100)
// element.position.y=centerPosition.y-Math.floor(cardIndex/5)*(cardSize.height+60)
// }
// return element
// }
export const useElementPosition = (element: any, count: number, cardSize: { width: number, height: number }, windowSize: { width: number, height: number }, cardIndex: number) => {
let xTable = 0
let yTable = 0
const centerPosition = {
x: 0,
y: windowSize.height / 2 - cardSize.height / 2
} }
const index =cardIndex%5 const index = cardIndex % 5
if(index==0){ if (index == 0) {
element.position.x=centerPosition.x xTable = centerPosition.x
element.position.y=centerPosition.y-Math.floor(cardIndex/5)*(cardSize.height+60) yTable = centerPosition.y - Math.floor(cardIndex / 5) * (cardSize.height + 60)
} }
else{ else {
element.position.x=index%2===0?Math.ceil(index/2)*(cardSize.width+100):-Math.ceil(index/2)*(cardSize.width+100) xTable = index % 2 === 0 ? Math.ceil(index / 2) * (cardSize.width + 100) : -Math.ceil(index / 2) * (cardSize.width + 100)
element.position.y=centerPosition.y-Math.floor(cardIndex/5)*(cardSize.height+60) yTable = centerPosition.y - Math.floor(cardIndex / 5) * (cardSize.height + 60)
} }
return { xTable, yTable }
return element
} }

67
src/icons/wave.svg Normal file
View File

@@ -0,0 +1,67 @@
<svg width="100%" height="100%" id="svg" viewBox="0 0 1440 690" xmlns="http://www.w3.org/2000/svg" class="transition duration-300 ease-in-out delay-150"><style>
.path-0{
animation:pathAnim-0 4s;
animation-timing-function: linear;
animation-iteration-count: infinite;
}
@keyframes pathAnim-0{
0%{
d: path("M 0,700 L 0,131 C 90.40769230769229,160.85641025641027 180.81538461538457,190.71282051282054 261,188 C 341.1846153846154,185.28717948717946 411.1461538461539,150.0051282051282 486,144 C 560.8538461538461,137.9948717948718 640.5999999999999,161.26666666666668 709,157 C 777.4000000000001,152.73333333333332 834.4538461538461,120.92820512820514 927,101 C 1019.5461538461539,81.07179487179486 1147.5846153846153,73.02051282051282 1239,80 C 1330.4153846153847,86.97948717948718 1385.2076923076925,108.9897435897436 1440,131 L 1440,700 L 0,700 Z");
}
25%{
d: path("M 0,700 L 0,131 C 72.08205128205125,98.84102564102564 144.1641025641025,66.68205128205128 230,70 C 315.8358974358975,73.31794871794872 415.4256410256411,112.11282051282052 509,130 C 602.5743589743589,147.88717948717948 690.1333333333332,144.86666666666665 752,144 C 813.8666666666668,143.13333333333335 850.0410256410258,144.4205128205128 923,134 C 995.9589743589742,123.57948717948719 1105.702564102564,101.45128205128205 1198,99 C 1290.297435897436,96.54871794871795 1365.148717948718,113.77435897435898 1440,131 L 1440,700 L 0,700 Z");
}
50%{
d: path("M 0,700 L 0,131 C 82.97692307692304,91.78461538461539 165.9538461538461,52.56923076923077 236,74 C 306.0461538461539,95.43076923076923 363.16153846153856,177.5076923076923 436,196 C 508.83846153846144,214.4923076923077 597.3999999999999,169.4 683,146 C 768.6000000000001,122.6 851.2384615384616,120.8923076923077 928,113 C 1004.7615384615384,105.1076923076923 1075.6461538461538,91.03076923076922 1160,93 C 1244.3538461538462,94.96923076923078 1342.1769230769232,112.98461538461538 1440,131 L 1440,700 L 0,700 Z");
}
75%{
d: path("M 0,700 L 0,131 C 87.95128205128205,141.17435897435897 175.9025641025641,151.34871794871793 241,163 C 306.0974358974359,174.65128205128207 348.34102564102557,187.77948717948718 435,190 C 521.6589743589744,192.22051282051282 652.7333333333335,183.53333333333333 737,160 C 821.2666666666665,136.46666666666667 858.725641025641,98.08717948717948 921,104 C 983.274358974359,109.91282051282052 1070.3641025641025,160.11794871794874 1161,172 C 1251.6358974358975,183.88205128205126 1345.8179487179486,157.44102564102565 1440,131 L 1440,700 L 0,700 Z");
}
100%{
d: path("M 0,700 L 0,131 C 90.40769230769229,160.85641025641027 180.81538461538457,190.71282051282054 261,188 C 341.1846153846154,185.28717948717946 411.1461538461539,150.0051282051282 486,144 C 560.8538461538461,137.9948717948718 640.5999999999999,161.26666666666668 709,157 C 777.4000000000001,152.73333333333332 834.4538461538461,120.92820512820514 927,101 C 1019.5461538461539,81.07179487179486 1147.5846153846153,73.02051282051282 1239,80 C 1330.4153846153847,86.97948717948718 1385.2076923076925,108.9897435897436 1440,131 L 1440,700 L 0,700 Z");
}
}</style><defs><linearGradient id="gradient" x1="0%" y1="50%" x2="100%" y2="50%"><stop offset="5%" stop-color="#7bdcb5"></stop><stop offset="95%" stop-color="#8ED1FC"></stop></linearGradient></defs><path d="M 0,700 L 0,131 C 90.40769230769229,160.85641025641027 180.81538461538457,190.71282051282054 261,188 C 341.1846153846154,185.28717948717946 411.1461538461539,150.0051282051282 486,144 C 560.8538461538461,137.9948717948718 640.5999999999999,161.26666666666668 709,157 C 777.4000000000001,152.73333333333332 834.4538461538461,120.92820512820514 927,101 C 1019.5461538461539,81.07179487179486 1147.5846153846153,73.02051282051282 1239,80 C 1330.4153846153847,86.97948717948718 1385.2076923076925,108.9897435897436 1440,131 L 1440,700 L 0,700 Z" stroke="none" stroke-width="0" fill="url(#gradient)" fill-opacity="0.4" class="transition-all duration-300 ease-in-out delay-150 path-0" transform="rotate(-180 720 350)"></path><style>
.path-1{
animation:pathAnim-1 4s;
animation-timing-function: linear;
animation-iteration-count: infinite;
}
@keyframes pathAnim-1{
0%{
d: path("M 0,700 L 0,306 C 73.36923076923077,283.31794871794875 146.73846153846154,260.63589743589745 217,254 C 287.26153846153846,247.36410256410255 354.4153846153846,256.77435897435896 436,279 C 517.5846153846154,301.22564102564104 613.6,336.26666666666665 708,351 C 802.4,365.73333333333335 895.1846153846154,360.15897435897443 971,349 C 1046.8153846153846,337.84102564102557 1105.6615384615386,321.09743589743584 1181,313 C 1256.3384615384614,304.90256410256416 1348.1692307692306,305.4512820512821 1440,306 L 1440,700 L 0,700 Z");
}
25%{
d: path("M 0,700 L 0,306 C 72.90000000000003,299.77435897435896 145.80000000000007,293.548717948718 232,306 C 318.19999999999993,318.451282051282 417.69999999999993,349.5794871794872 489,343 C 560.3000000000001,336.4205128205128 603.4000000000001,292.1333333333333 683,289 C 762.5999999999999,285.8666666666667 878.7,323.88717948717954 971,325 C 1063.3,326.11282051282046 1131.8,290.3179487179487 1206,281 C 1280.2,271.6820512820513 1360.1,288.8410256410257 1440,306 L 1440,700 L 0,700 Z");
}
50%{
d: path("M 0,700 L 0,306 C 102.84615384615384,278.4230769230769 205.69230769230768,250.84615384615387 274,272 C 342.3076923076923,293.15384615384613 376.0769230769231,363.03846153846155 458,364 C 539.9230769230769,364.96153846153845 670.0000000000001,297 744,299 C 817.9999999999999,301 835.9230769230769,372.96153846153845 918,370 C 1000.0769230769231,367.03846153846155 1146.3076923076924,289.15384615384613 1244,266 C 1341.6923076923076,242.84615384615387 1390.8461538461538,274.4230769230769 1440,306 L 1440,700 L 0,700 Z");
}
75%{
d: path("M 0,700 L 0,306 C 101.82564102564103,310.93589743589746 203.65128205128207,315.87179487179486 277,326 C 350.34871794871793,336.12820512820514 395.2205128205129,351.448717948718 469,357 C 542.7794871794871,362.551282051282 645.4666666666666,358.3333333333333 735,341 C 824.5333333333334,323.6666666666667 900.9128205128204,293.21794871794873 972,284 C 1043.0871794871796,274.78205128205127 1108.8820512820512,286.79487179487177 1186,294 C 1263.1179487179488,301.20512820512823 1351.5589743589744,303.6025641025641 1440,306 L 1440,700 L 0,700 Z");
}
100%{
d: path("M 0,700 L 0,306 C 73.36923076923077,283.31794871794875 146.73846153846154,260.63589743589745 217,254 C 287.26153846153846,247.36410256410255 354.4153846153846,256.77435897435896 436,279 C 517.5846153846154,301.22564102564104 613.6,336.26666666666665 708,351 C 802.4,365.73333333333335 895.1846153846154,360.15897435897443 971,349 C 1046.8153846153846,337.84102564102557 1105.6615384615386,321.09743589743584 1181,313 C 1256.3384615384614,304.90256410256416 1348.1692307692306,305.4512820512821 1440,306 L 1440,700 L 0,700 Z");
}
}</style><defs><linearGradient id="gradient" x1="0%" y1="50%" x2="100%" y2="50%"><stop offset="5%" stop-color="#7bdcb5"></stop><stop offset="95%" stop-color="#8ED1FC"></stop></linearGradient></defs><path d="M 0,700 L 0,306 C 73.36923076923077,283.31794871794875 146.73846153846154,260.63589743589745 217,254 C 287.26153846153846,247.36410256410255 354.4153846153846,256.77435897435896 436,279 C 517.5846153846154,301.22564102564104 613.6,336.26666666666665 708,351 C 802.4,365.73333333333335 895.1846153846154,360.15897435897443 971,349 C 1046.8153846153846,337.84102564102557 1105.6615384615386,321.09743589743584 1181,313 C 1256.3384615384614,304.90256410256416 1348.1692307692306,305.4512820512821 1440,306 L 1440,700 L 0,700 Z" stroke="none" stroke-width="0" fill="url(#gradient)" fill-opacity="0.53" class="transition-all duration-300 ease-in-out delay-150 path-1" transform="rotate(-180 720 350)"></path><style>
.path-2{
animation:pathAnim-2 4s;
animation-timing-function: linear;
animation-iteration-count: infinite;
}
@keyframes pathAnim-2{
0%{
d: path("M 0,700 L 0,481 C 83.87692307692308,501.28205128205127 167.75384615384615,521.5641025641025 243,530 C 318.24615384615385,538.4358974358975 384.86153846153843,535.025641025641 459,514 C 533.1384615384616,492.974358974359 614.8,454.33333333333337 695,455 C 775.2,455.66666666666663 853.9384615384615,495.6410256410257 931,494 C 1008.0615384615385,492.3589743589743 1083.446153846154,449.1025641025641 1168,440 C 1252.553846153846,430.8974358974359 1346.2769230769231,455.94871794871796 1440,481 L 1440,700 L 0,700 Z");
}
25%{
d: path("M 0,700 L 0,481 C 100.42051282051281,464.76666666666665 200.84102564102562,448.53333333333336 276,458 C 351.1589743589744,467.46666666666664 401.05641025641023,502.6333333333333 459,510 C 516.9435897435898,517.3666666666667 582.9333333333334,496.93333333333334 679,472 C 775.0666666666666,447.06666666666666 901.2102564102565,417.6333333333333 991,420 C 1080.7897435897435,422.3666666666667 1134.225641025641,456.53333333333336 1203,472 C 1271.774358974359,487.46666666666664 1355.8871794871795,484.23333333333335 1440,481 L 1440,700 L 0,700 Z");
}
50%{
d: path("M 0,700 L 0,481 C 80.45897435897433,478.6948717948718 160.91794871794866,476.38974358974355 227,489 C 293.08205128205134,501.61025641025645 344.7871794871796,529.1358974358975 439,515 C 533.2128205128204,500.8641025641025 669.9333333333332,445.06666666666666 762,426 C 854.0666666666668,406.93333333333334 901.4794871794875,424.59743589743584 976,431 C 1050.5205128205125,437.40256410256416 1152.1487179487178,432.5435897435898 1234,439 C 1315.8512820512822,445.4564102564102 1377.9256410256412,463.2282051282051 1440,481 L 1440,700 L 0,700 Z");
}
75%{
d: path("M 0,700 L 0,481 C 91.47179487179488,453.0820512820512 182.94358974358977,425.1641025641025 260,429 C 337.05641025641023,432.8358974358975 399.69743589743587,468.4256410256411 485,497 C 570.3025641025641,525.5743589743589 678.2666666666668,547.1333333333333 750,532 C 821.7333333333332,516.8666666666667 857.2358974358974,465.04102564102567 933,442 C 1008.7641025641026,418.95897435897433 1124.7897435897435,424.7025641025641 1216,436 C 1307.2102564102565,447.2974358974359 1373.6051282051283,464.14871794871794 1440,481 L 1440,700 L 0,700 Z");
}
100%{
d: path("M 0,700 L 0,481 C 83.87692307692308,501.28205128205127 167.75384615384615,521.5641025641025 243,530 C 318.24615384615385,538.4358974358975 384.86153846153843,535.025641025641 459,514 C 533.1384615384616,492.974358974359 614.8,454.33333333333337 695,455 C 775.2,455.66666666666663 853.9384615384615,495.6410256410257 931,494 C 1008.0615384615385,492.3589743589743 1083.446153846154,449.1025641025641 1168,440 C 1252.553846153846,430.8974358974359 1346.2769230769231,455.94871794871796 1440,481 L 1440,700 L 0,700 Z");
}
}</style><defs><linearGradient id="gradient" x1="0%" y1="50%" x2="100%" y2="50%"><stop offset="5%" stop-color="#7bdcb5"></stop><stop offset="95%" stop-color="#8ED1FC"></stop></linearGradient></defs><path d="M 0,700 L 0,481 C 83.87692307692308,501.28205128205127 167.75384615384615,521.5641025641025 243,530 C 318.24615384615385,538.4358974358975 384.86153846153843,535.025641025641 459,514 C 533.1384615384616,492.974358974359 614.8,454.33333333333337 695,455 C 775.2,455.66666666666663 853.9384615384615,495.6410256410257 931,494 C 1008.0615384615385,492.3589743589743 1083.446153846154,449.1025641025641 1168,440 C 1252.553846153846,430.8974358974359 1346.2769230769231,455.94871794871796 1440,481 L 1440,700 L 0,700 Z" stroke="none" stroke-width="0" fill="url(#gradient)" fill-opacity="1" class="transition-all duration-300 ease-in-out delay-150 path-2" transform="rotate(-180 720 350)"></path></svg>

After

Width:  |  Height:  |  Size: 12 KiB

View File

@@ -175,3 +175,4 @@ export const defaultImageList = [
url: 'https://24years.top/resource/image/image5.png' url: 'https://24years.top/resource/image/image5.png'
} }
] ]
export const defaultPatternList=[19,20,21,38,55,54,53,70,87,88,89,23,40,57,74,91,92,93,76,59,42,25,24,27,28,29,46,63,62,61,78,95,96,97,31,48,65,66,67,33,50,84,101]

View File

@@ -1,5 +1,5 @@
import { defineStore } from 'pinia'; import { defineStore } from 'pinia';
import { defaultMusicList,defaultImageList } from './data' import { defaultMusicList,defaultImageList,defaultPatternList } from './data'
import {IMusic,IImage} from '@/types/storeType'; import {IMusic,IImage} from '@/types/storeType';
// import { IPrizeConfig } from '@/types/storeType'; // import { IPrizeConfig } from '@/types/storeType';
export const useGlobalConfig = defineStore('global', { export const useGlobalConfig = defineStore('global', {
@@ -17,7 +17,9 @@ export const useGlobalConfig = defineStore('global', {
cardHeight: 200, cardHeight: 200,
textColor: '#ffffff', textColor: '#ffffff',
luckyCardColor:'#ECB1AC', luckyCardColor:'#ECB1AC',
textSize: 30 textSize: 30,
patternColor:'#1b66c9',
patternList:defaultPatternList as number[],
}, },
musicList: defaultMusicList as IMusic[], musicList: defaultMusicList as IMusic[],
imageList:defaultImageList as IImage[], imageList:defaultImageList as IImage[],
@@ -68,6 +70,14 @@ export const useGlobalConfig = defineStore('global', {
getTextSize(state) { getTextSize(state) {
return state.globalConfig.theme.textSize; return state.globalConfig.theme.textSize;
}, },
// 获取图案颜色
getPatterColor(state){
return state.globalConfig.theme.patternColor;
},
// 获取图案列表
getPatternList(state){
return state.globalConfig.theme.patternList;
},
// 获取音乐列表 // 获取音乐列表
getMusicList(state) { getMusicList(state) {
return state.globalConfig.musicList; return state.globalConfig.musicList;
@@ -122,6 +132,18 @@ export const useGlobalConfig = defineStore('global', {
setTextSize(textSize: number) { setTextSize(textSize: number) {
this.globalConfig.theme.textSize = textSize; this.globalConfig.theme.textSize = textSize;
}, },
// 设置图案颜色
setPatterColor(patterColor: string) {
this.globalConfig.theme.patternColor = patterColor;
},
// 设置图案列表
setPatternList(patternList: number[]) {
this.globalConfig.theme.patternList = patternList;
},
// 重置图案列表
resetPatternList() {
this.globalConfig.theme.patternList = defaultPatternList;
},
// 添加音乐 // 添加音乐
addMusic(music: IMusic) { addMusic(music: IMusic) {
// 验证音乐是否已存在看name字段 // 验证音乐是否已存在看name字段
@@ -200,7 +222,9 @@ export const useGlobalConfig = defineStore('global', {
cardWidth: 200, cardWidth: 200,
cardHeight: 140, cardHeight: 140,
textColor: '#ffffff', textColor: '#ffffff',
textSize: 30 textSize: 30,
patternColor: '#1b66c9',
patternList:defaultPatternList,
}, },
musicList: defaultMusicList as IMusic[], musicList: defaultMusicList as IMusic[],

View File

@@ -1,10 +1,12 @@
import {usePersonConfig} from './personConfig'; import {usePersonConfig} from './personConfig';
import { usePrizeConfig } from './prizeConfig'; import { usePrizeConfig } from './prizeConfig';
import {useGlobalConfig} from './globalConfig'; import {useGlobalConfig} from './globalConfig';
import {useSystem} from './system';
export default function useStore() { export default function useStore() {
return { return {
personConfig:usePersonConfig(), personConfig:usePersonConfig(),
prizeConfig:usePrizeConfig(), prizeConfig:usePrizeConfig(),
globalConfig:useGlobalConfig() globalConfig:useGlobalConfig(),
system:useSystem(),
}; };
} }

View File

@@ -63,7 +63,6 @@ export const usePersonConfig = defineStore('person', {
// person.prizeTime = new Date().toString() // person.prizeTime = new Date().toString()
} }
}); });
console.log('person;;',person)
this.personConfig.alreadyPersonList.push(person); this.personConfig.alreadyPersonList.push(person);
}); });
}, },

30
src/store/system.ts Normal file
View File

@@ -0,0 +1,30 @@
import { defineStore } from 'pinia';
// import { IPrizeConfig } from '@/types/storeType';
export const useSystem = defineStore('system', {
state() {
return {
isMobile:false
};
},
getters: {
getIsMobile(state) {
return state.isMobile;
},
},
actions: {
setIsMobile(isMobile: boolean) {
this.isMobile = isMobile;
},
},
persist: {
enabled: true,
strategies: [
{
// 如果要存储在localStorage中
// storage: localStorage,
// key: 'globalConfig',
// paths: ['globalConfig'],
},
],
},
})

View File

@@ -1,7 +1,6 @@
.element-card { .element-card {
cursor: default; cursor: default;
text-align: center; text-align: center;
.card-id { .card-id {
position: absolute; position: absolute;
top: 20px; top: 20px;
@@ -30,14 +29,18 @@
.lucky-element-card { .lucky-element-card {
cursor: default; cursor: default;
text-align: center; text-align: center;
&::before {
background-color: linear-gradient(-45deg, #e81cff 0%, #40c9ff 100%);
border: 1px solid linear-gradient(-45deg, #e81cff 0%, #40c9ff 100%);
}
.lucky-card-id { .card-id {
position: absolute; position: absolute;
top: 20px; top: 20px;
right: 20px; right: 20px;
} }
.lucky-card-name { .card-name {
position: absolute; position: absolute;
top: 40px; top: 40px;
left: 0px; left: 0px;
@@ -46,9 +49,12 @@
white-space: nowrap; white-space: nowrap;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
// -webkit-animation: tracking-in-expand-fwd 0.8s cubic-bezier(0.215, 0.61, 0.355, 1) both;
// animation: tracking-in-expand-fwd 0.8s cubic-bezier(0.215, 0.61, 0.355, 1) both;
// animation-delay: 0.6s;
} }
.lucky-card-detail { .card-detail {
position: absolute; position: absolute;
left: 0; left: 0;
right: 0; right: 0;

View File

@@ -3,6 +3,7 @@ export interface IPersonConfig {
uid: string; uid: string;
name: string; name: string;
department:string; department:string;
identity:string;
isWin:boolean; isWin:boolean;
x:number; x:number;
y:number y:number

View File

@@ -27,3 +27,12 @@ export const addOtherInfo=(personList:any[])=>{
return personList return personList
} }
export const selectCard=(cardIndexArr:number[],tableLength:number,personId:number):number=>{
const cardIndex = Math.round(Math.random() * (tableLength-1));
if(cardIndexArr.includes(cardIndex)){
return selectCard(cardIndexArr,tableLength,personId)
}
return cardIndex
}

View File

@@ -9,10 +9,11 @@ import daisyuiThemes from 'daisyui/src/theming/themes'
import { ColorPicker } from 'vue3-colorpicker'; import { ColorPicker } from 'vue3-colorpicker';
import 'vue3-colorpicker/style.css'; import 'vue3-colorpicker/style.css';
import { isRgbOrRgba, isHex } from '@/utils/color' import { isRgbOrRgba, isHex } from '@/utils/color'
import PatternSetting from './components/PatternSetting.vue'
const globalConfig = useStore().globalConfig const globalConfig = useStore().globalConfig
const personConfig = useStore().personConfig const personConfig = useStore().personConfig
const {getTopTitle:topTitle, getTheme: localTheme, getCardColor: cardColor,getLuckyColor:luckyCardColor, getTextColor: textColor, getCardSize: cardSize, getTextSize: textSize, getRowCount: rowCount,getIsShowPrizeList:isShowPrizeList } = storeToRefs(globalConfig) const { getTopTitle: topTitle, getTheme: localTheme, getPatterColor: patternColor, getPatternList: patternList, getCardColor: cardColor, getLuckyColor: luckyCardColor, getTextColor: textColor, getCardSize: cardSize, getTextSize: textSize, getRowCount: rowCount, getIsShowPrizeList: isShowPrizeList } = storeToRefs(globalConfig)
const { getAlreadyPersonList: alreadyPersonList, getNotPersonList: notPersonList } = storeToRefs(personConfig) const { getAlreadyPersonList: alreadyPersonList, getNotPersonList: notPersonList } = storeToRefs(personConfig)
const colorPickerRef = ref() const colorPickerRef = ref()
@@ -21,7 +22,7 @@ interface ThemeDaType {
} }
const isRowCountChange = ref(0) //0未改变1改变,2加载中 const isRowCountChange = ref(0) //0未改变1改变,2加载中
const themeValue = ref(localTheme.value.name) const themeValue = ref(localTheme.value.name)
const topTitleValue= ref(structuredClone(topTitle.value)) const topTitleValue = ref(structuredClone(topTitle.value))
const cardColorValue = ref(structuredClone(cardColor.value)) const cardColorValue = ref(structuredClone(cardColor.value))
const luckyCardColorValue = ref(structuredClone(luckyCardColor.value)) const luckyCardColorValue = ref(structuredClone(luckyCardColor.value))
const textColorValue = ref(structuredClone(textColor.value)) const textColorValue = ref(structuredClone(textColor.value))
@@ -29,6 +30,7 @@ const cardSizeValue = ref(structuredClone(cardSize.value))
const textSizeValue = ref(structuredClone(textSize.value)) const textSizeValue = ref(structuredClone(textSize.value))
const rowCountValue = ref(structuredClone(rowCount.value)) const rowCountValue = ref(structuredClone(rowCount.value))
const isShowPrizeListValue = ref(structuredClone(isShowPrizeList.value)) const isShowPrizeListValue = ref(structuredClone(isShowPrizeList.value))
const patternColorValue = ref(structuredClone(patternColor.value))
const themeList = ref(Object.keys(daisyuiThemes)) const themeList = ref(Object.keys(daisyuiThemes))
const daisyuiThemeList = ref<ThemeDaType>(daisyuiThemes) const daisyuiThemeList = ref<ThemeDaType>(daisyuiThemes)
const formData = ref({ const formData = ref({
@@ -72,11 +74,19 @@ const resetPersonLayout = () => {
const newNotPersonList = newList.slice(alreadyLen, notLen + alreadyLen) const newNotPersonList = newList.slice(alreadyLen, notLen + alreadyLen)
personConfig.deleteAllPerson() personConfig.deleteAllPerson()
personConfig.addNotPersonList(newNotPersonList) personConfig.addNotPersonList(newNotPersonList)
personConfig.addAlreadyPersonList(newAlreadyPersonList,null) personConfig.addAlreadyPersonList(newAlreadyPersonList, null)
isRowCountChange.value = 0 isRowCountChange.value = 0
}, 1000) }, 1000)
} }
const clearPattern = () => {
globalConfig.setPatternList([] as number[])
}
const resetPattern = () => {
globalConfig.resetPatternList()
}
// const handleChangeShowFields = (fieldItem: any) => { // const handleChangeShowFields = (fieldItem: any) => {
// formData.value.showField.map((item) => { // formData.value.showField.map((item) => {
// if (item.label === fieldItem.label) { // if (item.label === fieldItem.label) {
@@ -97,18 +107,18 @@ watch(() => formData.value.rowCount, () => {
formErr.value.rowCount = err.issues[0].message formErr.value.rowCount = err.issues[0].message
}) })
}) })
watch(topTitleValue,(val)=>{ watch(topTitleValue, (val) => {
globalConfig.setTopTitle(val) globalConfig.setTopTitle(val)
}), }),
watch(themeValue, (val: any) => { watch(themeValue, (val: any) => {
const selectedThemeDetail = daisyuiThemeList.value[val] const selectedThemeDetail = daisyuiThemeList.value[val]
globalConfig.setTheme({ name: val, detail: selectedThemeDetail }) globalConfig.setTheme({ name: val, detail: selectedThemeDetail })
themeChange(val) themeChange(val)
if (selectedThemeDetail.primary && (isHex(selectedThemeDetail.primary) || isRgbOrRgba(selectedThemeDetail.primary))) { if (selectedThemeDetail.primary && (isHex(selectedThemeDetail.primary) || isRgbOrRgba(selectedThemeDetail.primary))) {
globalConfig.setCardColor(selectedThemeDetail.primary) globalConfig.setCardColor(selectedThemeDetail.primary)
} }
}, { deep: true }) }, { deep: true })
watch(cardColorValue, (val: string) => { watch(cardColorValue, (val: string) => {
globalConfig.setCardColor(val) globalConfig.setCardColor(val)
@@ -116,7 +126,9 @@ watch(cardColorValue, (val: string) => {
watch(luckyCardColorValue, (val: string) => { watch(luckyCardColorValue, (val: string) => {
globalConfig.setLuckyCardColor(val) globalConfig.setLuckyCardColor(val)
}, { deep: true }) }, { deep: true })
watch(patternColorValue, (val: string) => {
globalConfig.setPatterColor(val)
})
watch(textColorValue, (val: string) => { watch(textColorValue, (val: string) => {
globalConfig.setTextColor(val) globalConfig.setTextColor(val)
}, { deep: true }) }, { deep: true })
@@ -124,9 +136,9 @@ watch(textColorValue, (val: string) => {
watch(cardSizeValue, (val: { width: number; height: number; }) => { watch(cardSizeValue, (val: { width: number; height: number; }) => {
globalConfig.setCardSize(val) globalConfig.setCardSize(val)
}, { deep: true }), }, { deep: true }),
watch(isShowPrizeListValue,()=>{ watch(isShowPrizeListValue, () => {
globalConfig.setIsShowPrizeList(isShowPrizeListValue.value) globalConfig.setIsShowPrizeList(isShowPrizeListValue.value)
}) })
onMounted(() => { onMounted(() => {
}) })
</script> </script>
@@ -183,7 +195,8 @@ onMounted(() => {
<div class="label"> <div class="label">
<span class="label-text">中奖卡片颜色</span> <span class="label-text">中奖卡片颜色</span>
</div> </div>
<ColorPicker ref="colorPickerRef" v-model="luckyCardColorValue" v-model:pure-color="luckyCardColorValue"></ColorPicker> <ColorPicker ref="colorPickerRef" v-model="luckyCardColorValue" v-model:pure-color="luckyCardColorValue">
</ColorPicker>
</label> </label>
<label class="w-full max-w-xs form-control"> <label class="w-full max-w-xs form-control">
@@ -225,11 +238,40 @@ onMounted(() => {
<input type="number" v-model="textSizeValue" placeholder="Type here" <input type="number" v-model="textSizeValue" placeholder="Type here"
class="w-full max-w-xs input input-bordered" /> class="w-full max-w-xs input input-bordered" />
</label> </label>
<label class="w-full max-w-xs form-control">
<div class="label">
<span class="label-text">高亮颜色</span>
</div>
<ColorPicker ref="colorPickerRef" v-model="patternColorValue" v-model:pure-color="patternColorValue">
</ColorPicker>
</label>
<label class="flex flex-row items-center w-full gap-24 mb-0 form-control">
<div>
<div class="label">
<span class="label-text">图案设置</span>
</div>
<div class="h-auto">
<PatternSetting :rowCount="rowCount" :cardColor="cardColor" :patternColor="patternColor"
:patternList="patternList"></PatternSetting>
</div>
</div>
</label>
<div class="flex w-full h-24 gap-3 m-0">
<button class="mt-5 btn btn-info btn-sm" @click.stop="clearPattern">
<span>清空图案设置</span>
</button>
<div class="tooltip" data-tip="默认图案设置针对17列时有效其他列数请自行设置">
<button class="mt-5 btn btn-info btn-sm" @click="resetPattern">
<span>默认图案设置</span>
</button>
</div>
</div>
<label class="w-full max-w-xs mb-10 form-control"> <label class="w-full max-w-xs mb-10 form-control">
<div class="label"> <div class="label">
<span class="label-text">是否常显奖品列表</span> <span class="label-text">是否常显奖品列表</span>
</div> </div>
<input type="checkbox" :checked="isShowPrizeListValue" @change="isShowPrizeListValue=!isShowPrizeListValue" <input type="checkbox" :checked="isShowPrizeListValue" @change="isShowPrizeListValue = !isShowPrizeListValue"
class="mt-2 border-solid checkbox checkbox-secondary border-1" /> class="mt-2 border-solid checkbox checkbox-secondary border-1" />
</label> </label>

View File

@@ -0,0 +1,57 @@
<script setup lang='ts'>
import {computed} from 'vue';
const props=defineProps({
rowCount:{
type:Number,
default:17
},
cardColor:{
type:String,
default:'#fff'
},
patternColor:{
type:String,
default:'#000'
},
patternList:{
type:Array,
default:()=>[]
}
})
const data=computed(()=>{
return props
})
const updatePatternList=(event:Event,item:number)=>{
if(data.value.patternList.includes(item)){
const index=data.value.patternList.indexOf(item)
data.value.patternList.splice(index,1)
}else{
data.value.patternList.push(item)
}
// emits
}
</script>
<template>
<div class="w-full h-auto" >
<ul class="pattern-list" :style="{gridTemplateColumns:'repeat('+data.rowCount+',1fr)'}">
<li @click.stop="(event)=>updatePatternList(event,item)" class="w-5 h-5" v-for="item in data.rowCount*7" :key="item" :style="{backgroundColor:data.patternList.includes(item)?data.patternColor:data.cardColor}">
</li>
</ul>
</div>
</template>
<style lang='scss' scoped>
.pattern-list{
margin: 0;
padding: 0;
display:grid;
grid-template-rows:repeat(7,1fr);
grid-gap:1px;
border:1px solid #000;
li{
cursor:pointer;
}
}
</style>

View File

@@ -20,7 +20,7 @@ const addPrize = () => {
id: new Date().getTime().toString(), id: new Date().getTime().toString(),
name: '奖项', name: '奖项',
sort: 0, sort: 0,
isAll: true, isAll: false,
count: 1, count: 1,
isUsedCount:0, isUsedCount:0,
picture: { picture: {

View File

@@ -64,7 +64,7 @@ const skip = (path: string) => {
</div> </div>
<footer class="p-10 rounded footer footer-center bg-base-200 text-base-content"> <footer class="p-10 rounded footer footer-center bg-base-200 text-base-content">
<nav class="grid grid-flow-col gap-4"> <nav class="grid grid-flow-col gap-4">
<a class="link link-hover">行有不得反求诸己</a> <a class="link link-hover cursor-pointer text-inherit" target="_blank" href="https://24years.top">行有不得反求诸己</a>
</nav> </nav>
<nav> <nav>
<div class="grid grid-flow-col gap-4"> <div class="grid grid-flow-col gap-4">

View File

@@ -8,8 +8,10 @@ import defaultPrizeImage from '@/assets/images/龙.png'
const prizeConfig = useStore().prizeConfig const prizeConfig = useStore().prizeConfig
const globalConfig = useStore().globalConfig const globalConfig = useStore().globalConfig
const system= useStore().system
const { getPrizeConfig: localPrizeList, getCurrentPrize: currentPrize } = storeToRefs(prizeConfig) const { getPrizeConfig: localPrizeList, getCurrentPrize: currentPrize } = storeToRefs(prizeConfig)
const {getIsShowPrizeList:isShowPrizeList}= storeToRefs(globalConfig) const {getIsShowPrizeList:isShowPrizeList}= storeToRefs(globalConfig)
const {getIsMobile:isMobile} = storeToRefs(system)
const prizeListRef = ref() const prizeListRef = ref()
const prizeListContainerRef = ref() const prizeListContainerRef = ref()
// 获取prizeListRef高度 // 获取prizeListRef高度
@@ -34,7 +36,7 @@ onMounted(() => {
<div class="flex items-center"> <div class="flex items-center">
<div ref="prizeListContainerRef"> <div ref="prizeListContainerRef">
<transition name="prize-list" :appear="true"> <transition name="prize-list" :appear="true">
<div v-if="prizeShow" class="flex items-center"> <div v-if="prizeShow&&!isMobile" class="flex items-center">
<ul class="flex flex-col gap-1 p-2 rounded-xl bg-slate-500/50" ref="prizeListRef"> <ul class="flex flex-col gap-1 p-2 rounded-xl bg-slate-500/50" ref="prizeListRef">
<li v-for="item in localPrizeList" :key="item.id" <li v-for="item in localPrizeList" :key="item.id"
:class="currentPrize.id == item.id ? 'current-prize' : ''"> :class="currentPrize.id == item.id ? 'current-prize' : ''">
@@ -55,13 +57,13 @@ onMounted(() => {
</li> </li>
</ul> </ul>
<div class="flex flex-col gap-3"> <div class="flex flex-col gap-3">
<div class="tooltip" data-tip="奖项列表"> <div class="tooltip tooltip-right" data-tip="奖项列表">
<div class="flex items-center w-6 h-8 rounded-r-lg cursor-pointer prize-option bg-slate-500/50" <div class="flex items-center w-6 h-8 rounded-r-lg cursor-pointer prize-option bg-slate-500/50"
@click="prizeShow = !prizeShow"> @click="prizeShow = !prizeShow">
<svg-icon name="arrow_left" class="w-full h-full"></svg-icon> <svg-icon name="arrow_left" class="w-full h-full"></svg-icon>
</div> </div>
</div> </div>
<div class="tooltip" data-tip="添加抽奖"> <div class="tooltip tooltip-right" data-tip="添加抽奖">
<div class="flex items-center w-6 h-8 rounded-r-lg cursor-pointer prize-option bg-slate-500/50" <div class="flex items-center w-6 h-8 rounded-r-lg cursor-pointer prize-option bg-slate-500/50"
@click="addTemporaryPrize"> @click="addTemporaryPrize">
<svg-icon name="add" class="w-full h-full"></svg-icon> <svg-icon name="add" class="w-full h-full"></svg-icon>
@@ -73,7 +75,7 @@ onMounted(() => {
</div> </div>
<transition name="prize-operate" :appear="true"> <transition name="prize-operate" :appear="true">
<div class="tooltip" data-tip="奖项列表" v-show="!prizeShow"> <div class="tooltip tooltip-right" data-tip="奖项列表" v-show="!prizeShow">
<div class="flex items-center w-6 h-8 rounded-r-lg cursor-pointer prize-option bg-slate-500/50" <div class="flex items-center w-6 h-8 rounded-r-lg cursor-pointer prize-option bg-slate-500/50"
@click="prizeShow = !prizeShow"> @click="prizeShow = !prizeShow">
<svg-icon name="arrow_right" class="w-full h-full"></svg-icon> <svg-icon name="arrow_right" class="w-full h-full"></svg-icon>

View File

@@ -4,13 +4,15 @@ import PrizeList from './PrizeList.vue'
import { useElementStyle, useElementPosition } from '@/hooks/useElement' import { useElementStyle, useElementPosition } from '@/hooks/useElement'
import StarsBackground from '@/components/StarsBackground/index.vue' import StarsBackground from '@/components/StarsBackground/index.vue'
import confetti from 'canvas-confetti' import confetti from 'canvas-confetti'
import { filterData } from '@/utils' import { filterData, selectCard } from '@/utils'
import {rgba} from '@/utils/color'
import { IPersonConfig } from '@/types/storeType'
// import * as THREE from 'three' // import * as THREE from 'three'
import {Scene,PerspectiveCamera,Object3D,Vector3} from 'three' import { Scene, PerspectiveCamera, Object3D, Vector3 } from 'three'
// import { // import {
// CSS3DRenderer, CSS3DObject // CSS3DRenderer, CSS3DObject
// } from 'three/examples/jsm/renderers/CSS3DRenderer.js'; // } from 'three/examples/jsm/renderers/CSS3DRenderer.js';
import {CSS3DRenderer, CSS3DObject} from 'three-css3d' import { CSS3DRenderer, CSS3DObject } from 'three-css3d'
// import { TrackballControls } from 'three/examples/jsm/controls/TrackballControls.js'; // import { TrackballControls } from 'three/examples/jsm/controls/TrackballControls.js';
import TrackballControls from 'three-trackballcontrols'; import TrackballControls from 'three-trackballcontrols';
// import TWEEN from 'three/examples/jsm/libs/tween.module.js'; // import TWEEN from 'three/examples/jsm/libs/tween.module.js';
@@ -29,7 +31,7 @@ const prizeConfig = useStore().prizeConfig
const { getAllPersonList: allPersonList, getNotPersonList: notPersonList } = storeToRefs(personConfig) const { getAllPersonList: allPersonList, getNotPersonList: notPersonList } = storeToRefs(personConfig)
const { getCurrentPrize: currentPrize } = storeToRefs(prizeConfig) const { getCurrentPrize: currentPrize } = storeToRefs(prizeConfig)
const { getTopTitle: topTitle, getCardColor: cardColor, getTextColor: textColor, getLuckyColor: luckyColor, getCardSize: cardSize, getTextSize: textSize, getRowCount: rowCount } = storeToRefs(globalConfig) const { getTopTitle: topTitle, getCardColor: cardColor,getPatterColor: patternColor, getPatternList: patternList, getTextColor: textColor, getLuckyColor: luckyColor, getCardSize: cardSize, getTextSize: textSize, getRowCount: rowCount } = storeToRefs(globalConfig)
const tableData = ref<any[]>([]) const tableData = ref<any[]>([])
// const tableData = ref<any[]>(JSON.parse(JSON.stringify(alreadyPersonList.value)).concat(JSON.parse(JSON.stringify(notPersonList.value)))) // const tableData = ref<any[]>(JSON.parse(JSON.stringify(alreadyPersonList.value)).concat(JSON.parse(JSON.stringify(notPersonList.value))))
const currentStatus = ref(0) // 0为初始状态 1为抽奖准备状态2为抽奖中状态3为抽奖结束状态 const currentStatus = ref(0) // 0为初始状态 1为抽奖准备状态2为抽奖中状态3为抽奖结束状态
@@ -53,7 +55,10 @@ const targets = {
}; };
const luckyTargets = ref<any[]>([]) const luckyTargets = ref<any[]>([])
const luckyCardList = ref<any[]>([]) const luckyCardList = ref<number[]>([])
let luckyCount = ref(10)
const intervalTimer = ref<any>(null)
// const currentPrizeValue = ref(JSON.parse(JSON.stringify(currentPrize.value))) // const currentPrizeValue = ref(JSON.parse(JSON.stringify(currentPrize.value)))
// 填充数据,填满七行 // 填充数据,填满七行
@@ -123,7 +128,7 @@ const init = () => {
detail.innerHTML = `${tableData.value[i].department}<br/>${tableData.value[i].identity}`; detail.innerHTML = `${tableData.value[i].department}<br/>${tableData.value[i].identity}`;
element.appendChild(detail); element.appendChild(detail);
element = useElementStyle(element, cardColor.value, cardSize.value, textSize.value) element = useElementStyle(element, tableData.value[i],i,patternList.value,patternColor.value, cardColor.value, cardSize.value, textSize.value)
const object = new CSS3DObject(element); const object = new CSS3DObject(element);
object.position.x = Math.random() * 4000 - 2000; object.position.x = Math.random() * 4000 - 2000;
object.position.y = Math.random() * 4000 - 2000; object.position.y = Math.random() * 4000 - 2000;
@@ -203,6 +208,13 @@ const init = () => {
const transform = (targets: any[], duration: number) => { const transform = (targets: any[], duration: number) => {
TWEEN.removeAll(); TWEEN.removeAll();
if(intervalTimer.value){
clearInterval(intervalTimer.value);
intervalTimer.value=null
randomBallData('sphere')
}
return new Promise((resolve) => {
const objLength = objects.value.length; const objLength = objects.value.length;
for (let i = 0; i < objLength; ++i) { for (let i = 0; i < objLength; ++i) {
let object = objects.value[i]; let object = objects.value[i];
@@ -220,10 +232,12 @@ const transform = (targets: any[], duration: number) => {
.start() .start()
.onComplete(() => { .onComplete(() => {
if (luckyCardList.value.length) { if (luckyCardList.value.length) {
luckyCardList.value.forEach((item: any) => { luckyCardList.value.forEach((cardIndex:any)=>{
return useElementStyle(item.element, cardColor.value, cardSize.value, textSize.value) const item = objects.value[cardIndex]
useElementStyle(item.element, {} as any,i,patternList.value,patternColor.value, cardColor.value, cardSize.value, textSize.value,'sphere')
}) })
} }
luckyTargets.value = [];
luckyCardList.value = []; luckyCardList.value = [];
canOperate.value = true canOperate.value = true
@@ -234,7 +248,13 @@ const transform = (targets: any[], duration: number) => {
new TWEEN.Tween({}) new TWEEN.Tween({})
.to({}, duration * 2) .to({}, duration * 2)
.onUpdate(render) .onUpdate(render)
.start(); .start()
.onComplete(() => {
canOperate.value = true
resolve('')
});
})
// 整体自动旋转 // 整体自动旋转
} }
function onWindowResize() { function onWindowResize() {
@@ -332,14 +352,18 @@ const enterLottery = async () => {
if (!canOperate.value) { if (!canOperate.value) {
return return
} }
// luckyCardList.value = [] if (!intervalTimer.value) {
// prizeConfig.setCurrentPrize(currentPrize.value) randomBallData()
}
if(patternList.value.length){
patternList.value.forEach((item:number)=>{
objects.value[item-1].element.style.backgroundColor = rgba(cardColor.value, Math.random() * 0.5 + 0.25)
})
}
canOperate.value = false canOperate.value = false
transform(targets.sphere, 1000) await transform(targets.sphere, 1000)
currentStatus.value = 1 currentStatus.value = 1
setTimeout(() => {
rollBall(0.1, 2000) rollBall(0.1, 2000)
}, 2000)
} }
// 开始抽奖 // 开始抽奖
const startLottery = () => { const startLottery = () => {
@@ -376,17 +400,16 @@ const stopLottery = async () => {
if (!canOperate.value) { if (!canOperate.value) {
return return
} }
clearInterval(intervalTimer.value)
intervalTimer.value = null
canOperate.value = false canOperate.value = false
TWEEN.removeAll(); // TWEEN.removeAll();
rollBall(0, 1) rollBall(0, 1)
currentStatus.value = 0
// 抽奖池是否为全体人员 // 抽奖池是否为全体人员
const personPool = currentPrize.value.isAll ? allPersonList.value : notPersonList.value const personPool = currentPrize.value.isAll ? allPersonList.value : notPersonList.value
// const notPersonListLength = personPool.length;
// 每次最多抽十个 // 每次最多抽十个
let luckyCount = 10
const leftover = currentPrize.value.count - currentPrize.value.isUsedCount const leftover = currentPrize.value.count - currentPrize.value.isUsedCount
leftover < luckyCount ? luckyCount = leftover : luckyCount leftover < luckyCount.value ? luckyCount.value = leftover : luckyCount
if (personPool.length < leftover) { if (personPool.length < leftover) {
toast.open({ toast.open({
message: '抽奖人数不够', message: '抽奖人数不够',
@@ -397,22 +420,19 @@ const stopLottery = async () => {
return; return;
} }
for (let i = 0; i < luckyCount; i++) { for (let i = 0; i < luckyCount.value; i++) {
if (personPool.length > 0) { if (personPool.length > 0) {
const randomIndex = Math.round(Math.random() * (personPool.length-1)) const randomIndex = Math.round(Math.random() * (personPool.length - 1))
luckyTargets.value.push(personPool[randomIndex]) luckyTargets.value.push(personPool[randomIndex])
console.log( // console.log(
'leftover:', leftover, '\n', // 'leftover:', leftover, '\n',
'luckyCount', luckyCount, '\n', // 'luckyCount', luckyCount, '\n',
'currentPrize.value.isUsedCount', currentPrize.value.isUsedCount, '\n', // 'currentPrize.value.isUsedCount', currentPrize.value.isUsedCount, '\n',
'randomIndex', randomIndex, '\n', // 'randomIndex', randomIndex, '\n',
'personPool.length - 1', personPool.length - 1, '\n', // 'personPool.length - 1', personPool.length - 1, '\n',
'personPool[randomIndex]', personPool[randomIndex], '\n', // 'personPool[randomIndex]', personPool[randomIndex], '\n',
) // )
console.log(
'cadd id:', personPool[randomIndex].id)
let luckyCard = objects.value[personPool[randomIndex].id]
luckyCardList.value.push(luckyCard)
personPool.splice(randomIndex, 1) personPool.splice(randomIndex, 1)
// console.log( // console.log(
@@ -420,18 +440,22 @@ const stopLottery = async () => {
// ) // )
} }
} }
const luckyCardListLength = luckyCardList.value.length;
const windowSize = { width: window.innerWidth, height: window.innerHeight } const windowSize = { width: window.innerWidth, height: window.innerHeight }
luckyCardListLength && luckyCardList.value.slice(-luckyCount).forEach((item: any, index: number) => { luckyTargets.value.forEach((person: IPersonConfig, index: number) => {
item.element = useElementStyle(item.element, luckyColor.value, { width: cardSize.value.width * 2, height: cardSize.value.height * 2 }, textSize.value * 2, 'lucky') let cardIndex = selectCard(luckyCardList.value, tableData.value.length, person.id)
item = useElementPosition(item, rowCount.value, { width: cardSize.value.width * 2, height: cardSize.value.height * 2 }, windowSize, index) luckyCardList.value.push(cardIndex)
let item = objects.value[cardIndex]
const { xTable, yTable } = useElementPosition(item, rowCount.value, { width: cardSize.value.width * 2, height: cardSize.value.height * 2 }, windowSize, index)
new TWEEN.Tween(item.position) new TWEEN.Tween(item.position)
.to({ .to({
x: item.x, x: xTable,
y: item.y, y: yTable,
z: 1000 z: 1000
}, 1000) }, 1200)
.easing(TWEEN.Easing.Exponential.InOut) .easing(TWEEN.Easing.Exponential.InOut)
.onStart(() => {
item.element = useElementStyle(item.element, person,cardIndex,patternList.value,patternColor.value, luckyColor.value, { width: cardSize.value.width * 2, height: cardSize.value.height * 2 }, textSize.value * 2, 'lucky')
})
.start() .start()
new TWEEN.Tween(item.rotation) new TWEEN.Tween(item.rotation)
.to({ .to({
@@ -446,22 +470,32 @@ const stopLottery = async () => {
resetCamera() resetCamera()
}) })
}) })
// currentPrize.value.isUsedCount += luckyCount
// if (currentPrize.value.isUsedCount >= currentPrize.value.count) {
// currentPrize.value.isUsed = true
// }
// luckyCardList.value = []
// personConfig.addAlreadyPersonList(luckyTargets.value, currentPrize.value) currentStatus.value = 3
// prizeConfig.updatePrizeConfig(currentPrize.value) }
// 继续
const continueLottery = async () => {
// currentPrize.value.isUsedCount += luckyCount.value
if (currentPrize.value.isUsedCount >= currentPrize.value.count) {
currentPrize.value.isUsed = true
}
personConfig.addAlreadyPersonList(luckyTargets.value, currentPrize.value)
prizeConfig.updatePrizeConfig(currentPrize.value)
// prizeConfig.setCurrentPrize(currentPrize.value) prizeConfig.setCurrentPrize(currentPrize.value)
luckyTargets.value = [] luckyCount.value = 10
await enterLottery()
// startLottery()
currentStatus.value = 1
}
const quitLottery = () => {
enterLottery()
currentStatus.value = 0
} }
// 庆祝动画 // 庆祝动画
const confettiFire = () => { const confettiFire = () => {
var duration = 3 * 1000; const duration = 3 * 1000;
var end = Date.now() + duration; const end = Date.now() + duration;
(function frame() { (function frame() {
// launch a few confetti from the left edge // launch a few confetti from the left edge
confetti({ confetti({
@@ -520,14 +554,32 @@ const setDefaultPersonList = () => {
// 刷新页面 // 刷新页面
window.location.reload() window.location.reload()
} }
// 随机替换数据
const randomBallData = (mod: 'default' | 'lucky' |'sphere'='default') => {
// 两秒执行一次
intervalTimer.value = setInterval(() => {
// 产生随机数数组
const cardRandomIndexArr = [Math.round(Math.random() * (tableData.value.length - 1)), Math.round(Math.random() * (tableData.value.length - 1)), Math.round(Math.random() * (tableData.value.length - 1))]
const personRandomIndexArr = [Math.round(Math.random() * (allPersonList.value.length - 1)), Math.round(Math.random() * (allPersonList.value.length - 1)), Math.round(Math.random() * (allPersonList.value.length - 1))]
for (let i = 0; i < cardRandomIndexArr.length; i++) {
objects.value[cardRandomIndexArr[i]].element = useElementStyle(objects.value[cardRandomIndexArr[i]].element, allPersonList.value[personRandomIndexArr[i]],cardRandomIndexArr[i],patternList.value,patternColor.value, cardColor.value, { width: cardSize.value.width, height: cardSize.value.height }, textSize.value,mod)
}
// const randomCardIndex = Math.round(Math.random() * (tableData.value.length - 1))
// const randomPersonIndex = Math.round(Math.random() * (allPersonList.value.length - 1))
// objects.value[randomCardIndex].element = useElementStyle(objects.value[randomCardIndex].element, allPersonList.value[randomPersonIndex], cardColor.value, { width: cardSize.value.width, height: cardSize.value.height }, textSize.value, 'default')
}, 200)
}
onMounted(() => { onMounted(() => {
initTableData(); initTableData();
init(); init();
animation(); animation();
containerRef.value!.style.color = `${textColor}` containerRef.value!.style.color = `${textColor}`
randomBallData()
}); });
onUnmounted(() => { onUnmounted(() => {
clearInterval(intervalTimer.value)
intervalTimer.value = null
}) })
// watch(() => currentPrize.value.isUsed, (val) => { // watch(() => currentPrize.value.isUsed, (val) => {
// if (val) { // if (val) {
@@ -552,8 +604,9 @@ onUnmounted(() => {
<!-- 选中菜单结构 start--> <!-- 选中菜单结构 start-->
<div id="menu"> <div id="menu">
<button class="btn-end " @click="enterLottery" v-if="currentStatus == 0 && tableData.length > 0">进入抽奖</button> <button class="btn-end " @click="enterLottery" v-if="currentStatus == 0 && tableData.length > 0">进入抽奖</button>
<div class="start">
<button class="btn-start" @click="startLottery" v-if="currentStatus == 1"><strong>开始</strong> <div class="start" v-if="currentStatus == 1">
<button class="btn-start" @click="startLottery"><strong>开始</strong>
<div id="container-stars"> <div id="container-stars">
<div id="stars"></div> <div id="stars"></div>
</div> </div>
@@ -567,7 +620,33 @@ onUnmounted(() => {
<button class="btn-end btn glass btn-lg" @click="stopLottery" v-if="currentStatus == 2">抽取幸运儿</button> <button class="btn-end btn glass btn-lg" @click="stopLottery" v-if="currentStatus == 2">抽取幸运儿</button>
<div v-if="currentStatus == 3" class="flex justify-center gap-6 enStop">
<div class="start">
<button class="btn-start" @click="continueLottery"><strong>继续</strong>
<div id="container-stars">
<div id="stars"></div>
</div>
<div id="glow">
<div class="circle"></div>
<div class="circle"></div>
</div>
</button>
</div>
<div class="start">
<button class="btn-cancel" @click="quitLottery"><strong>取消</strong>
<div id="container-stars">
<div id="stars"></div>
</div>
<div id="glow">
<div class="circle"></div>
<div class="circle"></div>
</div>
</button>
</div>
</div>
<!-- <button id="table" @click="transform(targets.table, 2000)">TABLE</button> --> <!-- <button id="table" @click="transform(targets.table, 2000)">TABLE</button> -->
<!-- <button id="helix" @click="transform(targets.helix, 2000)">HELIX</button> --> <!-- <button id="helix" @click="transform(targets.helix, 2000)">HELIX</button> -->
@@ -591,7 +670,15 @@ onUnmounted(() => {
margin: 0 auto; margin: 0 auto;
font-size: 32px; font-size: 32px;
} }
// .enter-enter-active{
// -webkit-animation: fade-in-fwd 0.6s cubic-bezier(0.390, 0.575, 0.565, 1.000) both;
// animation: fade-in-fwd 0.6s cubic-bezier(0.390, 0.575, 0.565, 1.000) both;
// animation-delay:0.5s ;
// }
// .enter-leave-active{
// -webkit-animation: swing-out-top-bck 0.45s cubic-bezier(0.600, -0.280, 0.735, 0.045) both;
// animation: swing-out-top-bck 0.45s cubic-bezier(0.600, -0.280, 0.735, 0.045) both;
// }
.start { .start {
// 居中 // 居中
display: flex; display: flex;
@@ -619,6 +706,25 @@ onUnmounted(() => {
animation: pulsate-fwd 1.2s ease-in-out infinite both; animation: pulsate-fwd 1.2s ease-in-out infinite both;
} }
.btn-cancel {
cursor: pointer;
display: flex;
justify-content: center;
align-items: center;
width: 13rem;
overflow: hidden;
height: 3rem;
background-size: 300% 300%;
backdrop-filter: blur(1rem);
border-radius: 5rem;
transition: 0.5s;
animation: gradient_301 5s ease infinite;
border: double 4px transparent;
background-image: linear-gradient(#212121, #212121), linear-gradient(137.48deg, #ffdb3b 10%, #FE53BB 45%, #8F51EA 67%, #0044ff 87%);
background-origin: border-box;
background-clip: content-box, border-box;
}
#container-stars { #container-stars {
position: absolute; position: absolute;
z-index: -1; z-index: -1;
@@ -795,6 +901,8 @@ strong {
text-shadow: 0 0 .5em var(--glow-color); text-shadow: 0 0 .5em var(--glow-color);
position: relative; position: relative;
transition: all 0.3s; transition: all 0.3s;
-webkit-animation: swing-in-top-fwd 0.5s cubic-bezier(0.175, 0.885, 0.320, 1.275) both;
animation: swing-in-top-fwd 0.5s cubic-bezier(0.175, 0.885, 0.320, 1.275) both;
} }
.btn-end::after { .btn-end::after {
@@ -858,4 +966,62 @@ strong {
-webkit-transform: scale(1); -webkit-transform: scale(1);
transform: scale(1); transform: scale(1);
} }
}</style> }
@-webkit-keyframes fade-in-fwd {
0% {
-webkit-transform: translateZ(-80px);
transform: translateZ(-80px);
opacity: 0;
}
100% {
-webkit-transform: translateZ(0);
transform: translateZ(0);
opacity: 1;
}
}
@keyframes fade-in-fwd {
0% {
-webkit-transform: translateZ(-80px);
transform: translateZ(-80px);
opacity: 0;
}
100% {
-webkit-transform: translateZ(0);
transform: translateZ(0);
opacity: 1;
}
}
@-webkit-keyframes swing-out-top-bck {
0% {
-webkit-transform: rotateX(0deg);
transform: rotateX(0deg);
-webkit-transform-origin: top;
transform-origin: top;
opacity: 1;
}
100% {
-webkit-transform: rotateX(-100deg);
transform: rotateX(-100deg);
-webkit-transform-origin: top;
transform-origin: top;
opacity: 0;
}
}
@keyframes swing-out-top-bck {
0% {
-webkit-transform: rotateX(0deg);
transform: rotateX(0deg);
-webkit-transform-origin: top;
transform-origin: top;
opacity: 1;
}
100% {
-webkit-transform: rotateX(-100deg);
transform: rotateX(-100deg);
-webkit-transform-origin: top;
transform-origin: top;
opacity: 0;
}
}
</style>

View File

@@ -5,3 +5,5 @@
-- 从全员或者未中奖中人抽取 -- 从全员或者未中奖中人抽取
-- 导出表格 -- 导出表格
手机端访问提示跳转PC端