diff --git a/frontend/src/pages/cloud-law/video-call.vue b/frontend/src/pages/cloud-law/video-call.vue
index 36c4473..41f5c02 100644
--- a/frontend/src/pages/cloud-law/video-call.vue
+++ b/frontend/src/pages/cloud-law/video-call.vue
@@ -7,8 +7,8 @@
-
-
+
+
-
+
+
+
+
+ {{ voiceInitial }}
+ {{ voiceName }}
+
+
+
+
-
-
- 视频咨询
- {{ formattedCode }}
-
-
-
- {{ stateText }}
-
+
+
+ {{ durationText }}
+ +
- {{ durationText }}
+
+ ‹
+
+
+ {{ durationText }}
+
+
+
+
+
+
+ 麦克风{{ audioEnabled ? '已开' : '已关' }}
+
+
+
+
+
+
+ 扬声器已开
+
-
-
- {{ videoEnabled ? '摄' : '关' }}
+
+
摄像头{{ videoEnabled ? '已开' : '已关' }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 摄像头已关
+
+
+
- 挂
+
挂断
-
-
- {{ audioEnabled ? '麦' : '静' }}
+
+
+
+
+
+
+
+
+
+
+ 麦克风{{ audioEnabled ? '已开' : '已关' }}
- 麦克风{{ audioEnabled ? '已开' : '已关' }}
@@ -99,6 +150,12 @@ import {
MEETING_ENDED_REASON_LABEL
} from '@/constants/meeting'
import VideoTile from '@/components/meeting/VideoTile.vue'
+import bgImage from '@/static/bg.png'
+import hangupIcon from '@/static/cacel.png'
+import voiceOnIcon from '@/static/vocie_calling_1.png'
+import voiceOffIcon from '@/static/vocie_stop.png'
+import videoOnIcon from '@/static/vodie_calling_1.png'
+import videoOffIcon from '@/static/vodie_stop.png'
const meetingStore = useMeetingStore()
const userStore = useUserStore()
@@ -130,6 +187,10 @@ const hostId = computed(() => meetingStore.currentRoom?.host_id || '')
const audioEnabled = computed(() => !!meetingStore.localAudioEnabled)
const videoEnabled = computed(() => !!meetingStore.localVideoEnabled)
const speakingMap = computed(() => meetingStore.speakingMap || {})
+const isVoiceMode = computed(() => !videoEnabled.value)
+const speakerIcon = voiceOnIcon
+const cameraIcon = computed(() => videoEnabled.value ? videoOnIcon : videoOffIcon)
+const micIcon = computed(() => audioEnabled.value ? voiceOnIcon : voiceOffIcon)
const entryInitial = computed(() => {
const name = userStore.userInfo?.nickname || userStore.userInfo?.username || '在'
@@ -226,6 +287,14 @@ const tiles = computed(() => {
const selfTile = computed(() => tiles.value.find(t => t.isLocal) || null)
const primaryTile = computed(() => tiles.value.find(t => !t.isLocal && t.videoTrack) || tiles.value.find(t => !t.isLocal) || 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
+ if (primaryTile.value && !primaryTile.value.isLocal) return primaryTile.value.name
+ return '在线律师'
+})
+const voiceAvatar = computed(() => voicePeer.value?.user_avatar || '')
+const voiceInitial = computed(() => String(voiceName.value || '在').slice(0, 1))
const isReady = computed(() => meetingStore.localState === MEETING_LOCAL_STATE_CONNECTED && !joinError.value && !ended.value)
@@ -467,6 +536,51 @@ onUnload(() => {
inset: 0;
background: #050b1d;
}
+.voice-stage {
+ position: absolute;
+ inset: 0;
+ display: flex;
+ align-items: flex-start;
+ justify-content: center;
+ overflow: hidden;
+}
+.voice-bg {
+ position: absolute;
+ inset: 0;
+ width: 100%;
+ height: 100%;
+}
+.voice-profile {
+ position: relative;
+ z-index: 2;
+ margin-top: calc(126rpx + env(safe-area-inset-top));
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+}
+.voice-avatar {
+ width: 132rpx;
+ height: 132rpx;
+ border-radius: 50%;
+ border: 4rpx solid rgba(255, 255, 255, 0.86);
+ box-shadow: 0 12rpx 36rpx rgba(0, 0, 0, 0.28);
+}
+.voice-avatar-fallback {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ background: linear-gradient(135deg, #43b1ff 0%, #1974e8 100%);
+ color: #ffffff;
+ font-size: 54rpx;
+ font-weight: 700;
+}
+.voice-name {
+ margin-top: 24rpx;
+ font-size: 28rpx;
+ line-height: 1;
+ color: #ffffff;
+ font-weight: 600;
+}
.main-video {
width: 100%;
height: 100%;
@@ -482,13 +596,13 @@ onUnload(() => {
}
.self-preview {
position: absolute;
- right: 24rpx;
- bottom: 218rpx;
- width: 210rpx;
- height: 280rpx;
- border-radius: 20rpx;
+ right: 30rpx;
+ top: calc(104rpx + env(safe-area-inset-top));
+ width: 220rpx;
+ height: 310rpx;
+ border-radius: 10rpx;
overflow: hidden;
- border: 2rpx solid rgba(108, 151, 255, 0.72);
+ border: 0;
box-shadow: 0 10rpx 40rpx rgba(0, 0, 0, 0.38);
background: #0b1220;
z-index: 5;
@@ -498,70 +612,78 @@ onUnload(() => {
height: 100%;
border-radius: 0;
}
-.top-info {
+.video-topbar {
position: absolute;
left: 0;
right: 0;
top: 0;
- padding: calc(26rpx + env(safe-area-inset-top)) 28rpx 40rpx;
+ height: calc(88rpx + env(safe-area-inset-top));
+ padding: env(safe-area-inset-top) 46rpx 0;
display: flex;
- align-items: flex-start;
+ align-items: center;
justify-content: space-between;
- gap: 20rpx;
background: linear-gradient(180deg, rgba(0, 0, 0, 0.55) 0%, rgba(0, 0, 0, 0) 100%);
box-sizing: border-box;
z-index: 6;
}
-.call-title {
- display: block;
- font-size: 32rpx;
- font-weight: 700;
- line-height: 1.2;
+.top-window-icon {
+ position: relative;
+ width: 42rpx;
+ height: 42rpx;
+ border: 4rpx solid rgba(255, 255, 255, 0.9);
+ border-radius: 6rpx;
+ box-sizing: border-box;
}
-.call-code {
- display: block;
- margin-top: 8rpx;
- font-size: 22rpx;
- color: rgba(255, 255, 255, 0.72);
- letter-spacing: 1rpx;
+.top-window-icon::after {
+ content: '';
+ position: absolute;
+ right: -16rpx;
+ bottom: -14rpx;
+ width: 24rpx;
+ height: 24rpx;
+ border: 4rpx solid rgba(255, 255, 255, 0.9);
+ border-radius: 5rpx;
+ box-sizing: border-box;
}
-.status-pill {
- display: inline-flex;
+.top-duration {
+ font-size: 36rpx;
+ color: #ffffff;
+ font-weight: 500;
+ text-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.35);
+}
+.top-plus {
+ color: #ffffff;
+ font-size: 56rpx;
+ line-height: 1;
+ font-weight: 300;
+}
+.voice-topbar {
+ position: absolute;
+ left: 0;
+ right: 0;
+ top: 0;
+ height: calc(88rpx + env(safe-area-inset-top));
+ padding: env(safe-area-inset-top) 26rpx 0;
+ display: flex;
align-items: center;
- gap: 8rpx;
- padding: 8rpx 16rpx;
- border-radius: 999rpx;
- background: rgba(21, 128, 61, 0.72);
- color: #baf7d0;
- font-size: 22rpx;
- white-space: nowrap;
+ box-sizing: border-box;
+ z-index: 6;
}
-.status-pill.connecting,
-.status-pill.reconnecting {
- background: rgba(37, 99, 235, 0.72);
- color: #dbeafe;
+.voice-back {
+ color: #ffffff;
+ font-size: 54rpx;
+ line-height: 1;
+ font-weight: 300;
}
-.status-pill.ended,
-.status-pill.leaving {
- background: rgba(107, 114, 128, 0.72);
- color: #f3f4f6;
-}
-.status-dot {
- width: 12rpx;
- height: 12rpx;
- border-radius: 50%;
- background: currentColor;
- box-shadow: 0 0 12rpx currentColor;
-}
-.timer {
+.voice-duration {
position: absolute;
left: 50%;
- bottom: 196rpx;
+ bottom: calc(216rpx + env(safe-area-inset-bottom));
transform: translateX(-50%);
- padding: 8rpx 20rpx;
+ padding: 10rpx 20rpx;
border-radius: 999rpx;
- background: rgba(255, 255, 255, 0.18);
- color: rgba(255, 255, 255, 0.86);
+ background: rgba(255, 255, 255, 0.16);
+ color: rgba(255, 255, 255, 0.78);
font-size: 24rpx;
line-height: 1;
z-index: 7;
@@ -571,51 +693,88 @@ onUnload(() => {
left: 0;
right: 0;
bottom: 0;
- padding: 34rpx 44rpx calc(34rpx + env(safe-area-inset-bottom));
- display: flex;
- align-items: center;
- justify-content: space-between;
- background: linear-gradient(0deg, rgba(4, 10, 27, 0.96) 0%, rgba(4, 10, 27, 0.72) 72%, rgba(4, 10, 27, 0) 100%);
box-sizing: border-box;
z-index: 8;
}
+.video-controls {
+ padding: 28rpx 64rpx calc(122rpx + env(safe-area-inset-bottom));
+ display: grid;
+ grid-template-columns: repeat(3, 1fr);
+ column-gap: 46rpx;
+ background: linear-gradient(0deg, rgba(0, 0, 0, 0.54) 0%, rgba(0, 0, 0, 0.22) 62%, rgba(0, 0, 0, 0) 100%);
+}
+.voice-controls {
+ padding: 0 74rpx calc(54rpx + env(safe-area-inset-bottom));
+ display: grid;
+ grid-template-columns: 1fr 132rpx 1fr;
+ align-items: end;
+ column-gap: 54rpx;
+ background: transparent;
+}
+.voice-control-col {
+ display: flex;
+ flex-direction: column;
+ gap: 36rpx;
+}
.control-item {
display: flex;
flex-direction: column;
align-items: center;
- gap: 14rpx;
- min-width: 150rpx;
+ gap: 18rpx;
}
.control-btn,
.hangup-btn {
- width: 108rpx;
- height: 108rpx;
+ width: 124rpx;
+ height: 124rpx;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
- color: #ffffff;
- box-shadow: inset 0 0 0 2rpx rgba(255, 255, 255, 0.08);
+ box-sizing: border-box;
}
-.control-btn {
- background: rgba(24, 64, 140, 0.9);
+.white-btn {
+ background: rgba(255, 255, 255, 0.96);
+ box-shadow: 0 10rpx 26rpx rgba(0, 0, 0, 0.18);
+}
+.dark-btn {
+ width: 104rpx;
+ height: 104rpx;
+ background: rgba(13, 36, 89, 0.78);
+ border: 1rpx solid rgba(255, 255, 255, 0.06);
+ box-shadow: inset 0 0 0 2rpx rgba(255, 255, 255, 0.04);
}
.control-btn.disabled {
- background: rgba(18, 32, 70, 0.94);
- color: rgba(255, 255, 255, 0.55);
+ opacity: 0.94;
}
.hangup-btn {
- background: #ff2727;
- box-shadow: 0 10rpx 34rpx rgba(255, 39, 39, 0.38);
+ width: 132rpx;
+ height: 132rpx;
+ background: #ff2f3f;
+ box-shadow: 0 14rpx 36rpx rgba(255, 47, 63, 0.38);
}
-.control-icon,
-.hangup-icon {
- font-size: 34rpx;
- font-weight: 700;
+.hangup-center {
+ position: absolute;
+ left: 50%;
+ bottom: calc(32rpx + env(safe-area-inset-bottom));
+ transform: translateX(-50%);
+}
+.control-image {
+ width: 58rpx;
+ height: 58rpx;
+}
+.dark-btn .control-image {
+ width: 50rpx;
+ height: 50rpx;
+}
+.hangup-image {
+ width: 74rpx;
+ height: 74rpx;
}
.control-label {
font-size: 24rpx;
- color: rgba(255, 255, 255, 0.74);
+ line-height: 1;
+ color: rgba(255, 255, 255, 0.82);
+ text-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.3);
}
.loading {
opacity: 0.68;