群视频通话

This commit is contained in:
2025-12-07 21:31:56 +08:00
parent 655a2bdd59
commit c26c3ad1be
3 changed files with 144 additions and 143 deletions

View File

@@ -1,31 +1,45 @@
<template>
<div
v-if="showBanner"
class="mx-4 mb-2 p-2 bg-gradient-to-r from-green-900/40 to-emerald-900/40 border border-green-500/20 rounded-xl flex items-center justify-between backdrop-blur-sm shadow-lg animate-fade-in-down"
class="mx-4 mb-2 p-3 bg-[#1e1e24]/90 border border-white/5 rounded-xl flex items-center justify-between shadow-lg backdrop-blur-md animate-fade-in-down group hover:bg-[#25252b] transition-colors"
>
<div class="flex items-center gap-3 px-2">
<!-- 动态波纹图标 -->
<div class="relative w-8 h-8 flex items-center justify-center">
<div class="flex items-center gap-4">
<!-- 动态图标 -->
<div class="relative w-10 h-10 flex-shrink-0">
<div class="absolute inset-0 bg-green-500 rounded-full opacity-20 animate-ping"></div>
<div class="relative w-8 h-8 rounded-full bg-green-500/20 flex items-center justify-center border border-green-500/30">
<i class="fas fa-video text-green-400 text-xs"></i>
<div class="relative w-full h-full rounded-full bg-gradient-to-br from-green-500 to-emerald-700 flex items-center justify-center text-white shadow-inner">
<i class="fas fa-video text-sm"></i>
</div>
</div>
<div>
<p class="text-green-100 text-xs font-bold tracking-wide">群通话进行中</p>
<p class="text-green-400/70 text-[10px] flex items-center gap-1">
<span class="w-1.5 h-1.5 rounded-full bg-green-500 inline-block"></span>
{{ participantsCount }} 人参与
</p>
<div class="flex flex-col">
<div class="flex items-center gap-2">
<span class="text-white font-bold text-sm tracking-wide">群通话进行中</span>
<span class="px-1.5 py-0.5 bg-green-500/20 text-green-400 text-[10px] rounded font-mono">{{ participantsCount }}人</span>
</div>
<!-- 头像堆叠 -->
<div class="flex -space-x-2 mt-1.5 overflow-hidden py-0.5 pl-0.5">
<div v-for="user in previewParticipants" :key="user.userId" class="relative transition-transform hover:scale-110 hover:z-10">
<Avatar
:name="user.name"
:avatar="user.avatar"
size="sm"
class="w-5 h-5 ring-2 ring-[#1e1e24]"
/>
</div>
<div v-if="participantsCount > 5" class="w-5 h-5 rounded-full bg-gray-700 text-[8px] text-white flex items-center justify-center ring-2 ring-[#1e1e24] font-medium">
+{{ participantsCount - 5 }}
</div>
</div>
</div>
</div>
<button
class="px-3 py-1.5 bg-green-600 hover:bg-green-500 text-white text-xs font-bold rounded-lg transition shadow-lg shadow-green-900/30 flex items-center gap-1 active:scale-95"
class="px-4 py-2 bg-white text-black text-xs font-bold rounded-lg transition hover:bg-gray-200 active:scale-95 flex items-center gap-1.5 shadow-lg shadow-white/5"
@click="groupWebRTC.joinCurrentCall()"
>
<i class="fas fa-phone-alt text-[10px]"></i>
<i class="fas fa-phone-alt"></i>
<span>加入</span>
</button>
</div>
@@ -34,6 +48,7 @@
<script setup lang="ts">
import { computed } from 'vue'
import { useGroupWebRTC } from '@/composables/useGroupWebRTC'
import Avatar from '@/components/common/Avatar.vue'
const props = defineProps<{
roomId: string
@@ -50,6 +65,7 @@ const showBanner = computed(() => {
})
const participantsCount = computed(() => participants.value.length)
const previewParticipants = computed(() => participants.value.slice(0, 5))
</script>
<style scoped>

View File

@@ -1,48 +1,66 @@
<template>
<Teleport to="body">
<!-- 全屏背景遮罩:磨砂玻璃效果 -->
<div
class="fixed z-[9999] top-8 right-8 w-80 bg-[#1e1e24] border border-gray-700 rounded-2xl shadow-2xl overflow-hidden animate-slide-in"
class="fixed inset-0 z-[10000] flex flex-col items-center justify-center bg-gray-900/80 backdrop-blur-xl animate-fade-in select-none"
>
<div class="p-6 flex flex-col items-center">
<!-- 头像区 -->
<div class="relative mb-4">
<!-- 动态背景光晕 -->
<div class="absolute inset-0 overflow-hidden pointer-events-none">
<div class="absolute top-1/4 left-1/4 w-96 h-96 bg-purple-500/20 rounded-full blur-[100px] animate-pulse-slow"></div>
<div class="absolute bottom-1/4 right-1/4 w-96 h-96 bg-blue-500/20 rounded-full blur-[100px] animate-pulse-slow delay-1000"></div>
</div>
<!-- 主要内容卡片 -->
<div class="relative z-10 flex flex-col items-center animate-slide-up">
<!-- 头像区域 (带波纹动画) -->
<div class="relative mb-8">
<div class="absolute inset-0 bg-white/10 rounded-full animate-ping-slow"></div>
<div class="absolute inset-[-10px] bg-white/5 rounded-full animate-ping-slower"></div>
<Avatar
:name="callState.inviterName"
size="xl"
class="ring-4 ring-gray-800 shadow-lg"
:avatar="callState.inviterAvatar"
size="2xl"
class="w-32 h-32 text-4xl shadow-2xl border-4 border-white/10 relative z-20"
/>
<div class="absolute -bottom-1 -right-1 w-6 h-6 bg-green-500 rounded-full border-4 border-gray-800 flex items-center justify-center">
<i class="fas fa-video text-white text-[10px]"></i>
<!-- 类型图标 -->
<div class="absolute bottom-0 right-0 w-10 h-10 bg-gradient-to-br from-green-400 to-emerald-600 rounded-full flex items-center justify-center shadow-lg z-30 border-4 border-gray-900">
<i class="fas" :class="callState.type === 'video' ? 'fa-video' : 'fa-phone-alt'"></i>
</div>
</div>
<h3 class="text-white font-bold text-lg mb-1">{{ callState.inviterName }}</h3>
<p class="text-gray-400 text-sm mb-6">邀请你进行群视频通话...</p>
<!-- 文本信息 -->
<h2 class="text-3xl font-bold text-white mb-2 tracking-tight">{{ callState.inviterName }}</h2>
<p class="text-gray-300 text-lg mb-12 flex items-center gap-2">
<span>邀请你加入群{{ callState.type === 'video' ? '视频' : '语音' }}通话</span>
<span class="flex gap-1">
<span class="w-1 h-1 bg-gray-400 rounded-full animate-bounce"></span>
<span class="w-1 h-1 bg-gray-400 rounded-full animate-bounce delay-100"></span>
<span class="w-1 h-1 bg-gray-400 rounded-full animate-bounce delay-200"></span>
</span>
</p>
<!-- 按钮区 -->
<div class="flex gap-4 w-full">
<button
class="flex-1 py-2.5 bg-red-500/10 hover:bg-red-500/20 text-red-500 rounded-xl font-medium transition flex items-center justify-center gap-2"
@click="groupWebRTC.rejectInvite()"
>
<i class="fas fa-times"></i>
拒绝
</button>
<!-- 操作按钮 -->
<div class="flex items-center gap-16">
<!-- 拒绝 -->
<div class="flex flex-col items-center gap-3 group cursor-pointer" @click="groupWebRTC.rejectInvite()">
<div class="w-16 h-16 rounded-full bg-red-500/20 group-hover:bg-red-500 text-red-500 group-hover:text-white flex items-center justify-center transition-all duration-300 backdrop-blur-md border border-red-500/30">
<i class="fas fa-times text-2xl"></i>
</div>
<span class="text-sm text-gray-400 group-hover:text-white transition-colors">拒绝</span>
</div>
<button
class="flex-1 py-2.5 bg-green-500 hover:bg-green-600 text-white rounded-xl font-medium transition shadow-lg shadow-green-500/20 flex items-center justify-center gap-2"
@click="groupWebRTC.acceptInvite()"
>
<i class="fas fa-video"></i>
接听
</button>
<!-- 接听 -->
<div class="flex flex-col items-center gap-3 group cursor-pointer" @click="groupWebRTC.acceptInvite()">
<div class="w-20 h-20 rounded-full bg-green-500 text-white flex items-center justify-center transition-all duration-300 shadow-lg shadow-green-500/40 group-hover:scale-110 group-hover:shadow-green-500/60 animate-pulse-border">
<i class="fas" :class="callState.type === 'video' ? 'fa-video' : 'fa-phone'"></i>
</div>
<span class="text-sm text-gray-400 group-hover:text-white transition-colors">接听</span>
</div>
</div>
</div>
<!-- 进度条倒计时 -->
<div class="h-1 bg-gray-800 w-full">
<div class="h-full bg-green-500 animate-progress origin-left"></div>
</div>
</div>
</Teleport>
</template>
@@ -56,19 +74,23 @@ const { callState } = groupWebRTC
</script>
<style scoped>
@keyframes slideIn {
from { transform: translateX(100%); opacity: 0; }
to { transform: translateX(0); opacity: 1; }
.animate-fade-in {
animation: fadeIn 0.5s ease-out;
}
.animate-slide-in {
animation: slideIn 0.4s cubic-bezier(0.16, 1, 0.3, 1);
.animate-slide-up {
animation: slideUp 0.6s cubic-bezier(0.16, 1, 0.3, 1);
}
.animate-ping-slow {
animation: ping 2s cubic-bezier(0, 0, 0.2, 1) infinite;
}
.animate-ping-slower {
animation: ping 3s cubic-bezier(0, 0, 0.2, 1) infinite;
}
.animate-pulse-slow {
animation: pulse 6s cubic-bezier(0.4, 0, 0.6, 1) infinite;
}
@keyframes progress {
from { transform: scaleX(1); }
to { transform: scaleX(0); }
}
.animate-progress {
animation: progress 30s linear forwards;
}
@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
@keyframes slideUp { from { transform: translateY(20px); opacity: 0; } to { transform: translateY(0); opacity: 1; } }
@keyframes pulse { 0%, 100% { opacity: 0.2; } 50% { opacity: 0.5; } }
</style>