视频会议

This commit is contained in:
duoaohui
2026-05-23 19:44:00 +08:00
parent 2568f15bda
commit d45d6d9d4e

View File

@@ -11,7 +11,7 @@
<view v-if="!isVoiceMode" class="remote-stage">
<VideoTile
v-if="primaryTile"
class="main-video"
class="main-video clean-video-tile"
:user-id="primaryTile.userId"
:name="primaryTile.name"
:is-local="primaryTile.isLocal"
@@ -38,24 +38,24 @@
</view>
</view>
<view v-if="!isVoiceMode && selfTile && primaryTile && !primaryTile.isLocal" class="self-preview">
<view v-if="!isVoiceMode && secondaryTile" class="self-preview" @click="swapPrimaryTile">
<VideoTile
class="self-video"
:user-id="selfTile.userId"
:name="selfTile.name"
:is-local="selfTile.isLocal"
:is-host="selfTile.isHost"
:audio-enabled="selfTile.audioEnabled"
:video-enabled="selfTile.videoEnabled"
:audio-track="selfTile.audioTrack"
:video-track="selfTile.videoTrack"
:is-speaking="!!speakingMap[selfTile.userId]"
class="self-video clean-video-tile"
:user-id="secondaryTile.userId"
:name="secondaryTile.name"
:is-local="secondaryTile.isLocal"
:is-host="secondaryTile.isHost"
:audio-enabled="secondaryTile.audioEnabled"
:video-enabled="secondaryTile.videoEnabled"
:audio-track="secondaryTile.audioTrack"
:video-track="secondaryTile.videoTrack"
:is-speaking="!!speakingMap[secondaryTile.userId]"
:compact="true"
/>
</view>
<view v-if="!isVoiceMode" class="video-topbar">
<view class="top-window-icon"></view>
<view class="top-window-icon" @click="swapPrimaryTile"></view>
<text class="top-duration">{{ durationText }}</text>
<text class="top-plus"></text>
</view>
@@ -127,6 +127,7 @@ const leaving = ref(false)
const startedAt = ref(0)
const nowTs = ref(Date.now())
const ended = ref(false)
const preferSelfMain = ref(false)
let timerHandle = null
let stateStopWatch = null
let videoRetryHandle = null
@@ -244,7 +245,16 @@ const tiles = computed(() => {
})
const selfTile = computed(() => tiles.value.find(t => t.isLocal) || null)
const primaryTile = computed(() => tiles.value.find(t => !t.isLocal && t.videoTrack) || selfTile.value || tiles.value.find(t => !t.isLocal))
const remoteTile = computed(() => tiles.value.find(t => !t.isLocal && t.videoTrack) || tiles.value.find(t => !t.isLocal) || null)
const primaryTile = computed(() => {
if (preferSelfMain.value && selfTile.value) return selfTile.value
return remoteTile.value || selfTile.value
})
const secondaryTile = computed(() => {
if (!primaryTile.value) return null
if (primaryTile.value.isLocal) return remoteTile.value
return selfTile.value
})
const voicePeer = computed(() => participants.value.find(p => !sameUser(p.user_id, myUserId.value)) || null)
const voiceName = computed(() => {
if (voicePeer.value?.user_name) return voicePeer.value.user_name
@@ -418,6 +428,11 @@ const scheduleVideoRetry = () => {
}, 800)
}
const swapPrimaryTile = () => {
if (!selfTile.value || !remoteTile.value) return
preferSelfMain.value = !preferSelfMain.value
}
const onMicToggle = async () => {
if (audioLoading.value || leaving.value) return
audioLoading.value = true
@@ -772,8 +787,8 @@ onUnload(() => {
}
.control-btn,
.hangup-btn {
width: 124rpx;
height: 124rpx;
width: 140rpx;
height: 140rpx;
border-radius: 50%;
display: flex;
align-items: center;
@@ -785,8 +800,8 @@ onUnload(() => {
box-shadow: 0 10rpx 26rpx rgba(0, 0, 0, 0.18);
}
.dark-btn {
width: 112rpx;
height: 112rpx;
width: 132rpx;
height: 132rpx;
background: rgba(22, 43, 105, 0.86);
border: 1rpx solid rgba(255, 255, 255, 0.06);
box-shadow: inset 0 0 0 2rpx rgba(255, 255, 255, 0.04);
@@ -795,22 +810,22 @@ onUnload(() => {
opacity: 0.94;
}
.hangup-btn {
width: 132rpx;
height: 132rpx;
width: 150rpx;
height: 150rpx;
background: #ff2f3f;
box-shadow: 0 14rpx 36rpx rgba(255, 47, 63, 0.38);
}
.control-image {
width: 58rpx;
height: 58rpx;
width: 76rpx;
height: 76rpx;
}
.dark-btn .control-image {
width: 50rpx;
height: 50rpx;
width: 68rpx;
height: 68rpx;
}
.hangup-image {
width: 74rpx;
height: 74rpx;
width: 92rpx;
height: 92rpx;
}
.control-label {
font-size: 24rpx;
@@ -821,4 +836,10 @@ onUnload(() => {
.loading {
opacity: 0.68;
}
.clean-video-tile :deep(.footer) {
display: none;
}
.clean-video-tile :deep(.tag-self) {
display: none;
}
</style>