From 1d552a3bad95caae4af15322df28e6240b797693 Mon Sep 17 00:00:00 2001
From: 罗广辉 <guanghui.luo@foxmail.com>
Date: Thu, 13 Aug 2026 15:32:06 +0800
Subject: [PATCH] feat: app视频封面图

---
 applications/mobile-web-view/src/appPages/voiceCallDetail/index.vue |  502 +++++++++++++++++++++++++++---------------------------
 1 files changed, 251 insertions(+), 251 deletions(-)

diff --git a/applications/mobile-web-view/src/appPages/voiceCallDetail/index.vue b/applications/mobile-web-view/src/appPages/voiceCallDetail/index.vue
index e0f8098..07e8e20 100644
--- a/applications/mobile-web-view/src/appPages/voiceCallDetail/index.vue
+++ b/applications/mobile-web-view/src/appPages/voiceCallDetail/index.vue
@@ -1,18 +1,6 @@
 <template>
 	<div class="call-container" :class="{'incoming-call': state === 'ringing'} ">
 		<div class="content-wrapper">
-			<!--		<div class="input-group">
-					<div class="input-item">
-						<span class="input-label">我的 userId:</span>
-						<input v-model="uid" class="input-field" />
-					</div>
-
-					<div class="input-item">
-						<span class="input-label">对方 userId:</span>
-						<input v-model="peerUid" class="input-field" />
-					</div>
-				</div>-->
-
 			<div class="button-group" v-if="false">
 				<button @click="connectWS" :disabled="connected" class="btn btn-connect">连接WS</button>
 			</div>
@@ -20,14 +8,21 @@
 			<div class="contactAvatar">
 				<img :src="defaultAvatar" alt=""></img>
 			</div>
+
+			<!--  联系人名称-->
+			<div class="contactName">
+				{{ contactName }}
+			</div>
+
 			<div class="status-group">
 				<strong v-if="state==='ringing'" class="status-text incoming-status">来电中...</strong>
 				<strong v-if="state==='calling'" class="status-text calling-status">呼叫中...</strong>
-				<!--	<strong class="status-text">状态:<span :style="{color: getStateColor(state)}">{{ state }}</span></strong>-->
 				<strong v-if="state==='in-call'" class="status-text">通话时长:{{ durationText }}</strong>
+				<!--  通话结束提示-->
+				<strong v-if="callEnded" class="status-text ended-status">{{ endMessage }}</strong>
 			</div>
 			<div class="button-group">
-				<button  @click="requestCall" :disabled="!connected || state!=='idle'" class="btn btn-call">呼叫</button>
+				<!-- <button v-if="state === 'idle' && !receiveParameters && !callEnded" @click="requestCall" :disabled="!connected" class="btn btn-call">呼叫</button> -->
 
 				<button v-if="state==='ringing'" @click="acceptCall" class="btn btn-accept incoming-accept">接听</button>
 				<button v-if="state==='ringing'" @click="rejectCall" class="btn btn-reject incoming-reject">拒绝</button>
@@ -37,18 +32,6 @@
 
 
 		</div>
-
-		<!--	<div class="tip-message">
-			<small>提示:若 getUserMedia 不可用,请用 https 或 localhost 访问页面。</small>
-			</div>-->
-
-		<!--	<div class="log-container">
-			<div class="log-box">
-				<div class="log-title">日志信息:</div>
-				<pre class="log-content">{{ logText }}</pre>
-			</div>
-			</div>-->
-
 		<audio ref="remoteAudio" autoplay class="hidden-audio"></audio>
 	</div>
 </template>
@@ -56,91 +39,28 @@
 <script setup>
 import { useRoute } from 'vue-router'
 import defaultAvatar from '@/appDataSource/appwork/defaultAvatar.svg'
+import { showToast } from 'vant'
 const route = useRoute()
 /** ✅ 你的 WS 地址前缀(后面拼 userId) */
-const WS_BASE = 'wss://wrj.shuixiongit.com/ws/chat?userId='
-
-// 解析URL参数
-const parseUrlParams = () => {
-	// 1. 优先从route.query.voiceparams获取参数
-	if (route.query && route.query.voiceparams) {
-		console.log('从route.query.voiceparams获取参数:', route.query.voiceparams);
-		try {
-			// 解码并解析voiceparams参数
-			const params = JSON.parse(decodeURIComponent(route.query.voiceparams));
-			console.log('解析后的voiceparams:', params);
-			
-			if (params.peerUid) {
-				peerUid.value = String(params.peerUid);
-				log('🔗 从voiceparams获取peerUid:', params.peerUid);
-			}
-			
-			// 如果是来电类型,直接触发来电状态
-			if (params.type === 'incoming') {
-				log('📞 voiceparams检测到来电,直接进入来电状态');
-				incomingFrom = String(params.from);
-				peerUid.value = incomingFrom;
-				acceptedByMe = false;
-				offeredByPeer = false;
-				
-				state.value = 'ringing';
-				log('📞 收到来电 call,来自', incomingFrom);
-				
-				// 开始来电提示(铃声和震动)
-				playRingtone();
-				startVibration();
-			}
-		} catch (e) {
-			log('❌ 解析voiceparams参数失败:', String(e));
-		}
-	}
-	
-	// 2. 同时保留原有的URL参数解析逻辑,作为备选
-	const url = new URL(window.location.href);
-	const paramsStr = url.searchParams.get('params');
-	if (paramsStr) {
-		try {
-			const params = JSON.parse(decodeURIComponent(paramsStr));
-			if (params.peerUid) {
-				peerUid.value = String(params.peerUid);
-				log('🔗 从URL参数获取peerUid:', params.peerUid);
-			}
-		} catch (e) {
-			log('❌ 解析URL参数失败:', String(e));
-		}
-	}
-}
-
-// 从URL参数或本地存储获取用户ID
-const getUserIdFromStorage = () => {
-	const userId = localStorage.getItem('userId') || sessionStorage.getItem('userId')
-	if (userId) {
-		log('🔗 从本地存储获取userId:', userId)
-		return userId
-	}
-	return '3' // 默认值
-}
-
-const uid = ref('3')
-const peerUid = ref('2')
+// const WS_BASE = 'ws://218.202.104.82:38201/ws/chat?userId='
+// const WS_BASE = 'ws://218.202.104.82:38201/ws/chat'
+const WS_BASE = 'ws://220.177.172.27:8100/webrtc/ws/chat'
+const newUserInfo = ref(null)
+const uid = ref('')
+const peerUid = ref('')
+// 联系人名称
+const contactName = ref('')
 
 const connected = ref(false)
 const state = ref('idle') // idle | calling | ringing | in-call
 const logText = ref('')
 const remoteAudio = ref(null)
-
-/**
- * 根据状态返回对应颜色
- */
-const getStateColor = (state) => {
-	const colors = {
-		'idle': '#666',
-		'calling': '#2196F3',
-		'ringing': '#FF9800',
-		'in-call': '#4CAF50'
-	}
-	return colors[state] || '#666'
-}
+// 通话结束相关
+const callEnded = ref(false)
+const endMessage = ref('对方已挂断')
+const endTimer = ref(null)
+// token 存储
+const accessToken = ref('')
 
 let ws = null
 let pc = null
@@ -169,87 +89,73 @@
 	if (timer) clearInterval(timer)
 	timer = null
 }
+// 解析URL参数
+const parseUrlParams = () => {
+	// 1. 优先从route.query.voiceparams获取参数
+	if (route.query && route.query.voiceparams) {
+		try {
+			// 解码并解析voiceparams参数
+			const params = JSON.parse(decodeURIComponent(route.query.voiceparams));
+			peerUid.value = String(params.peerUid);
+			contactName.value = params.callerName || '未知联系人'
+			// 如果是来电类型,直接触发来电状态
+			if (params.type === 'incoming') {
+				log('📞 voiceparams检测到来电,直接进入来电状态');
+				incomingFrom = String(params.from);
+				peerUid.value = incomingFrom;
+				acceptedByMe = false;
+				offeredByPeer = false;
+
+				state.value = 'ringing';
+				log('📞 收到来电 call,来自', incomingFrom);
+
+			
+			}
+		} catch (e) {
+			log('❌ 解析voiceparams参数失败:', String(e));
+		}
+	}
+
+	// 2. 同时保留原有的URL参数解析逻辑,作为备选
+	// const url = new URL(window.location.href);
+	// const paramsStr = url.searchParams.get('params');
+	// if (paramsStr) {
+	// 	try {
+	// 		const params = JSON.parse(decodeURIComponent(paramsStr));
+	// 		if (params.peerUid) {
+	// 			peerUid.value = String(params.peerUid);
+	// 			log('🔗 从URL参数获取peerUid:', params.peerUid);
+	// 		}
+	// 	} catch (e) {
+	// 		log('❌ 解析URL参数失败:', String(e));
+	// 	}
+	// }
+}
+
+// 从URL参数或本地存储获取用户ID
+const getUserIdFromStorage = () => {
+	const userId = '2021474815063486465'
+	try {
+		const params = JSON.parse(decodeURIComponent(route.query.params));
+		newUserInfo.value = params.new_userInfo
+		const userIdFromParams = params.new_userInfo?.userId
+		console.log('从url获取用户id', userIdFromParams)
+		return userIdFromParams || userId
+	} catch (error) {
+		return userId
+	}
+}
 
 // 心跳
 let pingTimer = null
-function startPing() {
-	stopPing()
-	// 每 25 秒发一次 ping(你后端有 PING/PONG)
-	pingTimer = setInterval(() => {
-		if (connected.value) send('ping', 'system', null)
-	}, 25000)
-}
+// function startPing() {
+// 	stopPing()
+// 	// 每 25 秒发一次 ping(你后端有 PING/PONG)
+// 	pingTimer = setInterval(() => {
+// 		if (connected.value) send('ping', 'system', null)
+// 	}, 25000)
+// }
 
-// 来电提示相关
-let ringtoneAudio = null
-let vibrationTimer = null
-
-// 播放来电铃声
-function playRingtone() {
-	// 创建音频对象(使用默认的系统提示音)
-	ringtoneAudio = new Audio('data:audio/wav;base64,UklGRigAAABXQVZFZm10IBAAAAABAAEARKwAAIhYAQACABAAZGF0YQQAAAAAAA==');
-	ringtoneAudio.loop = true;
-	ringtoneAudio.volume = 0.5;
-
-	try {
-		ringtoneAudio.play();
-		log('🔊 开始播放来电铃声')
-	} catch (e) {
-		log('❌ 播放来电铃声失败:', String(e))
-	}
-}
-
-// 停止来电铃声
-function stopRingtone() {
-	if (ringtoneAudio) {
-		try {
-			ringtoneAudio.pause();
-			ringtoneAudio.currentTime = 0;
-			ringtoneAudio = null;
-			log('🔇 停止播放来电铃声')
-		} catch (e) {
-			log('❌ 停止来电铃声失败:', String(e))
-		}
-	}
-}
-
-// 开始震动
-function startVibration() {
-	// 检查浏览器是否支持震动 API
-	if ('vibrate' in navigator) {
-		// 震动模式:震动1秒,暂停0.5秒,重复
-		const vibrationPattern = [1000, 500];
-
-		try {
-			navigator.vibrate(vibrationPattern);
-			vibrationTimer = setInterval(() => {
-				navigator.vibrate(vibrationPattern);
-			}, 1500); // 每1.5秒重复一次震动模式
-			log('📳 开始震动提示')
-		} catch (e) {
-			log('❌ 震动失败:', String(e))
-		}
-	} else {
-		log('ℹ️ 当前浏览器不支持震动功能')
-	}
-}
-
-// 停止震动
-function stopVibration() {
-	if (vibrationTimer) {
-		clearInterval(vibrationTimer);
-		vibrationTimer = null;
-	}
-
-	if ('vibrate' in navigator) {
-		try {
-			navigator.vibrate(0); // 停止震动
-			log('📳 停止震动提示')
-		} catch (e) {
-			log('❌ 停止震动失败:', String(e))
-		}
-	}
-}
 function stopPing() {
 	if (pingTimer) clearInterval(pingTimer)
 	pingTimer = null
@@ -284,7 +190,14 @@
 
 function createPC() {
 	pc = new RTCPeerConnection({
-		iceServers: [{ urls: 'stun:stun.l.google.com:19302' }],
+		iceServers: [{ urls: 'stun:stun.l.google.com:19302' },
+			{ urls: 'stun:stun.l.google.com:19302' },
+			{ urls: 'stun:stun1.l.google.com:19302' },
+			{ urls: 'stun:stun.stunprotocol.org:3478' },
+			// 添加多个公共TURN服务器以提高跨网络连接成功率
+			{ urls: ['turn:freeturn.net:80', 'turn:freeturn.net:443'], username: 'free', credential: 'free' },
+			// 备用TURN服务器
+			{ urls: 'turn:turn.cloudlifter.io:443', username: 'webrtc', credential: 'webrtc' }],
 	})
 
 	pc.onicecandidate = (e) => {
@@ -292,7 +205,7 @@
 			send('candidate', peerUid.value, { candidate: e.candidate.toJSON ? e.candidate.toJSON() : e.candidate })
 		}
 	}
-
+// 步骤七:建立连接
 	pc.ontrack = (e) => {
 		log('✅ 收到远端音频流')
 		const stream = e.streams[0]
@@ -307,7 +220,7 @@
 		log('pc.connectionState =', pc.connectionState)
 	}
 }
-
+// 步骤六:连接音频
 async function getLocalAudio() {
 	if (localStream) return localStream
 
@@ -317,15 +230,47 @@
 	}
 
 	try {
-		localStream = await navigator.mediaDevices.getUserMedia({ audio: true })
-		log('✅ 已获取本地麦克风')
+		// 尝试使用完整约束
+		try {
+			localStream = await navigator.mediaDevices.getUserMedia({
+				audio: {
+					echoCancellation: true,
+					noiseSuppression: true,
+					autoGainControl: true,
+					channelCount: 1,
+					sampleRate: 16000,
+					sampleSize: 16
+				}
+			})
+			log('✅ 已获取本地麦克风(标准约束)')
+		} catch (strictError) {
+			// 如果标准约束失败,尝试最简单的约束
+			log('⚠️ 标准约束失败,尝试简化约束:', String(strictError))
+			localStream = await navigator.mediaDevices.getUserMedia({
+				audio: true
+			})
+			log('✅ 已获取本地麦克风(简化约束)')
+		}
 		return localStream
 	} catch (e) {
 		log('❌ 获取麦克风失败:', String(e))
+
+		// 提供更详细的错误信息
+		if (e.name === 'NotReadableError') {
+			log('❌ NotReadableError: 麦克风可能被其他应用占用,或权限未正确配置')
+			showToast('麦克风被占用或权限未授予')
+		} else if (e.name === 'NotAllowedError') {
+			log('❌ NotAllowedError: 用户拒绝了麦克风权限')
+			showToast('请授予麦克风权限')
+		} else if (e.name === 'NotFoundError') {
+			log('❌ NotFoundError: 未找到麦克风设备')
+			showToast('未找到麦克风设备')
+		}
+
 		throw e
 	}
 }
-
+// 步骤5 确保本地音频流已添加
 /** ✅ 关键:只 addTrack 一次,避免 “sender already exists” */
 async function ensureLocalTracksAdded() {
 	if (!pc) createPC()
@@ -346,7 +291,7 @@
 
 	return stream
 }
-
+// 步骤4 发送本地音频流
 async function flushCandidates() {
 	if (!pc || !pc.remoteDescription) return
 	while (pendingCandidates.length) {
@@ -362,8 +307,6 @@
 /* ---------------- 信令处理 ---------------- */
 
 async function onSignal(msg) {
-console.log('1cesss',msg);
-
 	if (!msg) return
 	const t = (msg.type || '').toString()
 
@@ -388,12 +331,7 @@
 		offeredByPeer = false
 
 		state.value = 'ringing'
-		log('📞 收到来电 call,来自', incomingFrom)
-
-		// 开始来电提示(铃声和震动)
-		playRingtone()
-		startVibration()
-
+			log('📞 收到来电 call,来自', incomingFrom)
 		return
 	}
 
@@ -423,12 +361,12 @@
 			lastOfferSdp = msg.payload?.sdp
 			return
 		}
-
+  // 步骤2
 		// 已接听:直接 answer
 		await answerOffer(msg.payload?.sdp, incomingFrom)
 		return
 	}
-
+// 步骤3 接收 answer
 	if (t === 'answer') {
 		log('✅ 收到 answer,通话建立')
 		if (!pc) createPC()
@@ -475,12 +413,14 @@
 
 	if (ws) ws.close()
 
-	ws = new WebSocket(WS_BASE + encodeURIComponent(uid.value))
-
+	// 使用从参数中获取的token或默认token
+	const token = accessToken.value
+	// ws = new WebSocket(WS_BASE + encodeURIComponent(uid.value))
+	ws = new WebSocket(WS_BASE, token)
 	ws.onopen = () => {
 		connected.value = true
 		log('WS 已连接 userId=', uid.value)
-		startPing()
+		// startPing()
 	}
 
 	ws.onclose = () => {
@@ -497,7 +437,7 @@
 		onSignal(msg)
 	}
 }
-
+// 发送呼叫信息
 function requestCall() {
 	state.value = 'calling'
 	incomingFrom = null
@@ -508,18 +448,15 @@
 	send('call', peerUid.value, null)
 	log('➡️ 发起呼叫 call 给', peerUid.value)
 }
-
+// 接收信息
 function acceptCall() {
 	if (!incomingFrom) return
 	acceptedByMe = true
 
-	// 停止来电提示
-	stopRingtone()
-	stopVibration()
-
 	// 先告诉对方我接听了(后端会把双方置忙)
 	send('accept', incomingFrom, null)
 	log('✅ 已点击接听,发送 accept 给', incomingFrom)
+
 
 	state.value = 'calling'
 
@@ -528,18 +465,19 @@
 		answerOffer(lastOfferSdp, incomingFrom)
 		lastOfferSdp = null
 	}
+	// 停止
+	const transmitData = { data: { sign:'closeBox' } }
+	uni.postMessage(transmitData)
 }
 
 function rejectCall() {
 	if (!incomingFrom) return
 
-	// 停止来电提示
-	stopRingtone()
-	stopVibration()
-
 	// 你后端没有 reject,用 busy 表示拒绝/不可接听
 	send('busy', incomingFrom, null)
 	log('❌ 已拒绝来电,发送 busy 给', incomingFrom)
+	const transmitData = { data: { type: 'hangupVoice',sign:'closeBox'  } }
+uni.postMessage(transmitData)
 
 	incomingFrom = null
 	acceptedByMe = false
@@ -560,14 +498,14 @@
 
 	// ✅ 不会重复 addTrack
 	await ensureLocalTracksAdded()
-
+// 步骤1:创建 offer
 	const offer = await pc.createOffer()
 	await pc.setLocalDescription(offer)
 
 	send('offer', peerUid.value, { sdp: pc.localDescription })
 	log('➡️ 已发送 offer 给', peerUid.value)
 }
-
+// 步骤2:等待 answer
 async function answerOffer(offerSdp, from) {
 	if (!offerSdp) {
 		log('❌ offer sdp 为空,无法接听')
@@ -591,6 +529,9 @@
 }
 
 function hangup() {
+	// 停止铃声
+// 	const transmitData = { data: { type: 'stopVoice' } }
+// uni.postMessage(transmitData)
 	cleanup(true)
 }
 
@@ -602,9 +543,6 @@
 	} catch {}
 
 	stopTimer()
-	// 停止来电提示
-	stopRingtone()
-	stopVibration()
 
 	if (pc) {
 		pc.getSenders().forEach(s => s.track && s.track.stop())
@@ -625,28 +563,70 @@
 
 	state.value = 'idle'
 
-	// 返回上一页(uni-app的语音通话列表页面)
-	if (window.uni) {
-		window.uni.navigateBack()
+	// 清除之前的定时器
+	if (endTimer.value) {
+		clearTimeout(endTimer.value)
+		endTimer.value = null
+	}
+
+	// 根据是谁发起的挂断决定不同的行为
+	if (sendToPeer) {
+		// 自己主动挂断:不提示,不延迟,直接跳转
+		log('⏰ 自己主动挂断,直接返回')
+		callEnded.value = false
+		// 返回上一页(uni-app的语音通话列表页面)
+		if (window.uni) {
+			window.uni.navigateBack()
+		} else {
+			log('❌ uni对象不存在,无法返回上一页')
+		}
+		const transmitData = { data: { type: 'hangupVoice' } }
+		uni.postMessage(transmitData)
 	} else {
-		log('❌ uni对象不存在,无法返回上一页')
+		// 对方挂断:显示提示,延迟10秒跳转
+		callEnded.value = true
+		endMessage.value = '对方已挂断'
+		const transmitData = { data: { type: 'hangupVoice',sign:'closeBox'  } }
+		uni.postMessage(transmitData)
+		// 延迟5秒后跳转页面
+		endTimer.value = setTimeout(() => {
+			// 返回上一页(uni-app的语音通话列表页面)
+			if (window.uni) {
+				window.uni.navigateBack()
+			} else {
+				log('❌ uni对象不存在,无法返回上一页')
+			}
+
+			// 重置通话结束状态
+			callEnded.value = false
+		}, 2000)
 	}
 }
 
+// 定义receiveParameters变量,用于模板中判断是否显示呼叫按钮
+const receiveParameters = ref(route.query.contact || null);
+
 onMounted(() => {
-console.log('收拾收拾',route.query.voiceparams);
-
-	const receiveParameters = route.query.contact
-	console.log('接收参数', receiveParameters)
-
-	// 解析并使用contact参数
-	if (receiveParameters) {
+	console.log('对方打给我的',route.query.voiceparams);
+	console.log('接收拨打电话:对方参数', receiveParameters)
+	if (route.query && route.query.params) {
 		try {
-			const contact = JSON.parse(decodeURIComponent(receiveParameters))
-			if (contact.friendId) {
-				peerUid.value = contact.friendId
-				log('🔗 从contact参数获取peerUid:', contact.friendId)
-				log('👤 联系人名称:', contact.friendNickName || '未知联系人')
+			const params = JSON.parse(decodeURIComponent(route.query.params));
+			// 获取token
+			if (params.access_token) {
+				accessToken.value = params.access_token;
+			}
+		} catch (e) {
+			log('❌ 解析params参数失败:', String(e));
+		}
+	}
+	// 解析并使用contact参数
+	if (receiveParameters.value) {
+		try {
+			const contact = JSON.parse(decodeURIComponent(receiveParameters.value))
+			if (contact.userId) {
+				peerUid.value = contact.userId
+				contactName.value = contact.nickName || '未知联系人'
 			}
 		} catch (e) {
 			log('❌ 解析contact参数失败:', String(e))
@@ -657,14 +637,16 @@
 	parseUrlParams()
 	// 自动连接WebSocket
 	connectWS()
-})
+});
 
-// 监听连接状态,连接成功后自动呼叫
-// watch(() => connected.value, (newVal) => {
-// 	if (newVal && state.value === 'idle') {
-// 		requestCall()
-// 	}
-// })
+// 监听连接状态,当connected变为true且有receiveParameters时自动呼叫
+watch(() => connected.value, (newVal) => {
+	if (newVal && state.value === 'idle' && receiveParameters.value) {
+		log('📞 连接成功且有contact参数,自动发起呼叫');
+		requestCall();
+	}
+});
+
 
 onBeforeUnmount(() => {
 	cleanup(false)
@@ -679,6 +661,9 @@
 	font-family: Arial, sans-serif;
 	background-color: #f5f5f5;
 	transition: all 0.3s ease;
+	display: flex;
+	align-items: center;
+	justify-content: center;
 }
 
 /* 来电时的全屏样式 */
@@ -693,15 +678,23 @@
 	padding: 0;
 }
 
+/* 通话结束状态样式 */
+.status-text.ended-status {
+	color: #e74c3c;
+	font-size: 18px;
+	font-weight: bold;
+	margin-top: 10px;
+	text-align: center;
+}
+
 .content-wrapper {
 	display: flex;
 	flex-direction: column;
-	gap: 20px;
+	gap: 30px;
 	max-width: 600px;
-	margin: 0 auto;
-	height: 100vh;
-	justify-content: center;
+	width: 100%;
 	align-items: center;
+	padding: 20px;
 }
 
 .input-group {
@@ -734,7 +727,7 @@
 	gap: 50px;
 	flex-wrap: wrap;
 	justify-content: center;
-	margin-top: 80px;
+	margin-top: 40px;
 }
 
 .btn {
@@ -816,8 +809,17 @@
 	font-size: 18px;
 	color: #333;
 	text-align: center;
-	margin-bottom: 20px;
+	margin-bottom: 10px;
 }
+
+	/* 联系人名称样式 */
+	.contactName {
+		font-size: 20px;
+		font-weight: bold;
+		color: #333;
+		text-align: center;
+		margin: 15px 0;
+	}
 
 /* 来电状态样式 */
 .status-text.incoming-status {
@@ -895,7 +897,6 @@
 	display: flex;
 	justify-content: center;
 	align-items: center;
-	margin-bottom: 40px;
 	border-radius: 50%;
 	background-color: #f0f0f0;
 	overflow: hidden;
@@ -908,10 +909,9 @@
 	}
 }
 
-/* 来电时的头像放大效果 */
+/* 来电时的头像样式 */
 .call-container.incoming-call .contactAvatar {
-	width: 220px;
-	height: 220px;
-	margin-bottom: 60px;
+	width: 180px;
+	height: 180px;
 }
-</style>
\ No newline at end of file
+</style>

--
Gitblit v1.9.3