websocket消息支持 (#188)

* Release (#162)

* feat:  websocket server demo

* feat:  ws server demo dev

* feat:  ws server and mobile page

* feat:  手机端发送消息

* feat:  手机网页发送消息

* 添加了抽奖中和抽奖完成时的音效

* feat:  自定义设置弹幕服务器地址

* feat:  ws not done

* fix: 🐛 fix pr-185 #185

为播放音效添加控制

* feat:  server worker demo not done

* feat:  websocket server

* feat:  全局接收websocket消息并存储到indexdb中

---------

Co-authored-by: Silence@2024 <707261624@qq.com>
This commit is contained in:
LOG1997
2026-01-09 17:11:43 +08:00
committed by GitHub
parent 52d2fcd0cb
commit 3eac4e1aac
40 changed files with 3489 additions and 279 deletions

View File

@@ -1,241 +1,50 @@
<script setup lang="ts">
import gsap from 'gsap'
import { ScrollTrigger } from 'gsap/ScrollTrigger'
import { onBeforeUnmount, onMounted, onUnmounted, ref } from 'vue'
import { onMounted, onUnmounted, ref, shallowRef, watch } from 'vue'
import { useToast } from 'vue-toast-notification'
import { api_sendMsg } from '@/api/msg'
import { getOriginUrl, getUniqueSignature } from '@/utils/auth'
gsap.registerPlugin(ScrollTrigger)
const toast = useToast()
const mobileUrl = shallowRef<string>('')
const wsQuery = ref<{ userSignature: string }>({
userSignature: '',
})
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,
},
})
function connectUserMsg() {
api_sendMsg(wsQuery.value.userSignature, `hello world ${wsQuery.value.userSignature}`).then((res: any) => {
toast.open({
message: res.msg || '发送成功',
type: 'success',
position: 'top-right',
})
}, scrollContainerRef.value) // <- Scope!
})
}
function disposeGsapAnimation() {
ctx.value.revert() // <- Easy Cleanup!
async function getFinger() {
const userSignature = await getUniqueSignature()
wsQuery.value.userSignature = userSignature
return userSignature
}
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
async function setMobileUrl() {
const originUrl = getOriginUrl()
const userSignature = await getFinger()
mobileUrl.value = `${originUrl}/log-lottery/mobile?userSignature=${userSignature}`
}
onMounted(() => {
initGsapAnimation()
listenScrollContainer()
})
onBeforeUnmount(() => {
removeScrollContainer()
getFinger()
setMobileUrl()
})
onUnmounted(() => {
disposeGsapAnimation()
})
</script>
<template>
<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 class="flex flex-col gap-3">
<button class="btn btn-primary btn-sm w-32" @click="connectUserMsg">
connectUserMsg
</button>
</div>
</template>
<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>
<style lang="scss" scoped></style>