96 UI optimization (#136)

* fix(home): 🐛 解决多次切换路由后页面卡顿的问题 #96

卸载路由时清除requestAnimationFrame

* feat:  文件存储使用Blob格式

* style: 💄 修改部分类型any为具体类型

* feat:  界面设置中模块使用瀑布流布局 #96

* fix: 🐛 md文档更换文件夹解决控制台警告

* style: 💄 switch按钮改回使用daisyui组件

* refactor: ♻️ 所有人员列表提取tableColumn

* style: 💄 奖项列表中的图片类型修复

* fix(globalConfig): 修复当前音乐项类型缺失问题

* feat:  single person not done

* feat:  可添加单人 #96

* build(.gitignore): 添加 auto-imports.d.ts 到忽略文件

* fix: 🐛 上传、下载excel文件时修复路径错误

打包成应用和网页端的baseUrl不一样,使用环境变量来表示

* fix: 🐛 导入人员列表时处理有值为空的情况

* style: 💄 改变toaster的组件

* fix: 🐛 上传文件、解析数据与存储/读取数据的处理

、

* fix(Config): 更新备案信息链接样式

将备案信息的段落标签替换为可点击的链接标签,使用户能够直接跳转到工信部备案查询页面。同时添加了悬停效果样式,提升用户体验。

* feat:  首页奖项列表样式修改 not done #96

* chore(deps): ✏️ 更新依赖版本

* chore: ✏️ gsap list demo

* build: 🏗️ docker构建优化

* chore: ✏️ gsap scroll demo

* style: 💄 gsap demno

* feat:  demo smooth scroll gsap scrolltrigger

* feat(Demo): 添加更多颜色选项并注释GSAP动画

* refactor(PrizeList): 重构奖品列表组件结构

* feat(PrizeList): 重构奖品列表组件并添加滚动动画

* feat:  增加定时抽取功能 #96

* feat:  添加定时抽取功能的说明

* feat:  优化gsap #96

项数不多时不触发gsap

* style: 💄 文本修改

* feat:  优化

* feat:  优化奖项列表

* fix(Home): 修复奖品列表滚动检测逻辑

* fix(home): 修复抽奖停止逻辑避免重复执行;调整卡片垂直居中位置计算

* feat:  播放中奖音频 #96
This commit is contained in:
LOG1997
2025-12-28 00:04:20 +08:00
committed by GitHub
parent a0223bda4f
commit bd5eac7d70
27 changed files with 4287 additions and 4439 deletions

View File

@@ -8,6 +8,7 @@ import { CSS3DObject, CSS3DRenderer } from 'three-css3d'
import { TrackballControls } from 'three/examples/jsm/controls/TrackballControls.js'
import { nextTick, onMounted, onUnmounted, ref } from 'vue'
import { useToast } from 'vue-toast-notification'
import enterAudio from '@/assets/audio/enter.wav'
import { useElementPosition, useElementStyle } from '@/hooks/useElement'
import i18n from '@/locales/i18n'
import useStore from '@/store'
@@ -16,6 +17,7 @@ import { rgba } from '@/utils/color'
import { LotteryStatus } from './type'
import { confettiFire, createSphereVertices, createTableVertices, getRandomElements, initTableData } from './utils'
const maxAudioLimit = 10
export function useViewModel() {
const toast = useToast()
// store里面存储的值
@@ -26,7 +28,21 @@ export function useViewModel() {
getNotThisPrizePersonList: notThisPrizePersonList,
} = storeToRefs(personConfig)
const { getCurrentPrize: currentPrize } = storeToRefs(prizeConfig)
const { getCardColor: cardColor, getPatterColor: patternColor, getPatternList: patternList, getTextColor: textColor, getLuckyColor: luckyColor, getCardSize: cardSize, getTextSize: textSize, getRowCount: rowCount, getIsShowAvatar: isShowAvatar, getTitleFont: titleFont, getTitleFontSyncGlobal: titleFontSyncGlobal } = storeToRefs(globalConfig)
const {
getCardColor: cardColor,
getPatterColor: patternColor,
getPatternList: patternList,
getTextColor: textColor,
getLuckyColor: luckyColor,
getCardSize: cardSize,
getTextSize: textSize,
getRowCount: rowCount,
getIsShowAvatar: isShowAvatar,
getTitleFont: titleFont,
getTitleFontSyncGlobal: titleFontSyncGlobal,
getDefiniteTime: definiteTime,
getWinMusic: isPlayWinMusic,
} = storeToRefs(globalConfig)
// three初始值
const ballRotationY = ref(0)
const containerRef = ref<HTMLElement>()
@@ -53,7 +69,7 @@ export function useViewModel() {
const intervalTimer = ref<any>(null)
const isInitialDone = ref<boolean>(false)
const animationFrameId = ref<any>(null)
const playingAudios = ref<HTMLAudioElement[]>([])
function initThreeJs() {
const felidView = 40
const width = window.innerWidth
@@ -367,14 +383,6 @@ export function useViewModel() {
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}人`,
@@ -385,6 +393,13 @@ export function useViewModel() {
})
currentStatus.value = LotteryStatus.running
rollBall(10, 3000)
if (definiteTime.value) {
setTimeout(() => {
if (currentStatus.value === LotteryStatus.running) {
stopLottery()
}
}, definiteTime.value * 1000)
}
}
/**
* @description: 停止抽奖,抽出幸运人
@@ -429,11 +444,41 @@ export function useViewModel() {
.easing(TWEEN.Easing.Exponential.InOut)
.start()
.onComplete(() => {
if (isPlayWinMusic.value) {
playWinMusic()
}
confettiFire()
resetCamera()
})
})
}
// 播放音频中将卡片越多audio对象越多声音越大
function playWinMusic() {
if (playingAudios.value.length > maxAudioLimit) {
console.log('音频播放数量已达到上限,请勿重复播放')
return
}
const enterNewAudio = new Audio(enterAudio)
playingAudios.value.push(enterNewAudio)
enterNewAudio.play()
.then(() => {
// 当音频播放结束后,从数组中移除
enterNewAudio.onended = () => {
const index = playingAudios.value.indexOf(enterNewAudio)
if (index > -1) {
playingAudios.value.splice(index, 1)
}
}
})
.catch((error) => {
console.error('播放音频失败:', error)
// 如果播放失败,也从数组中移除
const index = playingAudios.value.indexOf(enterNewAudio)
if (index > -1) {
playingAudios.value.splice(index, 1)
}
})
}
/**
* @description: 继续,意味着这抽奖作数,计入数据库
*/
@@ -441,7 +486,6 @@ export function useViewModel() {
if (!canOperate.value) {
return
}
const customCount = currentPrize.value.separateCount
if (customCount && customCount.enable && customCount.countList.length > 0) {
for (let i = 0; i < customCount.countList.length; i++) {
@@ -627,11 +671,6 @@ export function useViewModel() {
intervalTimer.value = null
window.removeEventListener('keydown', listenKeyboard)
})
// watch(() => allPersonList.value, (newVal) => {
// if (newVal.length) {
// init()
// }
// })
return {
setDefaultPersonList,