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

@@ -1,18 +1,241 @@
<script setup lang='ts'>
import WaterFall from '@/components/Waterfall/index.vue'
<script setup lang="ts">
import gsap from 'gsap'
import { ScrollTrigger } from 'gsap/ScrollTrigger'
import { onBeforeUnmount, onMounted, onUnmounted, ref } from 'vue'
gsap.registerPlugin(ScrollTrigger)
const list = ref<any[]>([])
list.value = [{
label: 1,
value: 1,
color: 'red',
}, {
label: 2,
value: 2,
color: 'blue',
}, {
label: 3,
value: 3,
color: 'yellow',
}, {
label: 4,
value: 4,
color: 'green',
}, {
label: 5,
value: 5,
color: 'pink',
}, {
label: 6,
value: 6,
color: 'orange',
}, {
label: 7,
value: 7,
color: 'purple',
}, {
label: 8,
value: 8,
color: 'brown',
}, {
label: 9,
value: 9,
color: 'gray',
}, {
label: 10,
value: 10,
color: 'cyan',
}, {
label: 11,
value: 11,
color: 'white',
}, {
label: 12,
value: 12,
color: 'black',
}, {
label: 13,
value: 13,
color: 'orange',
}, {
label: 14,
value: 14,
color: 'yellow',
}, {
label: 15,
value: 14,
color: 'pink',
}, {
label: 15,
value: 15,
color: 'orange',
}, {
label: 16,
value: 16,
color: 'yellow',
}, {
label: 17,
value: 17,
color: 'green',
}, {
label: 18,
value: 18,
color: 'purple',
}]
// 为每个 li 元素创建引用
const liRefs = ref()
const scrollContainerRef = ref()
const ctx = ref()
const showUpButton = ref(false)
const showDownButton = ref(true)
function initGsapAnimation() {
ctx.value = gsap.context(() => {
liRefs.value.forEach((box: any) => {
gsap.fromTo(box, { rotationX: -90, rotateZ: -20, opacity: 0 }, {
rotationX: 0,
rotateZ: 0,
opacity: 1,
scrollTrigger: {
trigger: box,
scroller: scrollContainerRef.value, // <- Specify the scroller!
start: 'bottom 100%',
end: 'top 70%',
scrub: true,
},
})
})
}, scrollContainerRef.value) // <- Scope!
}
function disposeGsapAnimation() {
ctx.value.revert() // <- Easy Cleanup!
}
function scrollHandler() {
const scrollHeight = scrollContainerRef.value.scrollHeight
const scrollTop = scrollContainerRef.value.scrollTop
const containerHeight = scrollContainerRef.value.clientHeight
// 滚动滑到底部
if (scrollTop + containerHeight >= scrollHeight) {
showDownButton.value = false
showUpButton.value = true
}
// 在中间
else if (scrollTop && scrollTop + containerHeight < scrollHeight) {
showDownButton.value = true
showUpButton.value = true
}
// 滚动滑到顶部
else {
showDownButton.value = true
showUpButton.value = false
}
}
function listenScrollContainer() {
scrollContainerRef.value.addEventListener('scroll', scrollHandler)
}
function removeScrollContainer() {
if (scrollContainerRef.value) {
scrollContainerRef.value.removeEventListener('scroll', scrollHandler)
}
}
function handleScroll(h: number) {
scrollContainerRef.value.scrollTop += h
}
onMounted(() => {
initGsapAnimation()
listenScrollContainer()
})
onBeforeUnmount(() => {
removeScrollContainer()
})
onUnmounted(() => {
disposeGsapAnimation()
})
</script>
<template>
<WaterFall>
<div class="bg-pink-500 h-20 w-48" />
<div class="bg-blue-500 h-30 w-48" />
<div class="bg-yellow-500 h-40 w-48" />
<div class="bg-green-500 h-20 w-48" />
<div class="bg-red-500 h-30 w-48" />
<div class="bg-purple-500 h-50 w-48" />
</WaterFall>
<div class="h-full w-48 flex flex-col justify-center overflow-hidden relative">
<div class="w-full h-16 flex justify-center scroll-button scroll-button-up">
<SvgIcon v-show="showUpButton" name="chevron-up" size="64px" class="text-gray-200/80 cursor-pointer" @click="handleScroll(-100)" />
</div>
<div ref="scrollContainerRef" class="h-150 w-48 overflow-y-auto overflow-x-hidden relative scroll-smooth hide-scrollbar">
<ul class="li-container relative bg-slate-500/50">
<li
v-for="item in list" :key="item.value" ref="liRefs" :style="{ backgroundColor: item.color }"
class="w-full h-28 text-center leading-30 cursor-pointer duration-300"
>
{{ item.label }}
</li>
<li class="h-16" />
</ul>
</div>
<div class="w-full h-16 flex justify-center scroll-button scroll-button-down">
<SvgIcon v-show="showDownButton" name="chevron-down" size="64px" class="text-gray-200/80 cursor-pointer" @click="handleScroll(100)" />
</div>
</div>
</template>
<style scoped>
<style lang="scss" scoped>
.scroll-button::before,
.scroll-button::after {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: -1;
transform: translate(12px 12px);
}
.scroll-button::before {
transform: translate(0, -6px);
opacity: 0.6;
}
.scroll-button::after {
transform: translate(0, 6px);
opacity: 0.4;
}
/* 添加动画效果 */
.scroll-button-down {
animation: bounce-down 2s infinite;
}
/* 添加动画效果 */
.scroll-button-up {
animation: bounce-up 2s infinite;
}
@keyframes bounce-down {
0%, 20%, 50%, 80%, 100% {
transform: translateY(0);
}
40% {
transform: translateY(-5px);
}
60% {
transform: translateY(-2px);
}
}
@keyframes bounce-up {
0%, 20%, 50%, 80%, 100% {
transform: translateY(0);
}
40% {
transform: translateY(5px);
}
60% {
transform: translateY(2px);
}
}
.scroll-button:hover {
transform: translateY(-3px);
}
</style>