style: DeviceScreen.tsx清理全部emoji符号

- 移除注释中所有emoji标记(checkmark/new/wrench/search等)
- 移除日志输出中的emoji(控制权/警告/错误等)
- 移除UI文本中的emoji(操作已禁用/丢帧警告/全屏按钮)
- 清理Vite缓存解决pendingSizeRef旧代码残留问题
This commit is contained in:
wdvipa
2026-02-15 18:51:03 +08:00
parent 5ce99d8708
commit bec7cd3979

View File

@@ -27,12 +27,12 @@ const DeviceScreen: React.FC<DeviceScreenProps> = ({ deviceId, onScreenSizeChang
const [imageSize, setImageSize] = useState<{ width: number, height: number } | null>(null) const [imageSize, setImageSize] = useState<{ width: number, height: number } | null>(null)
const [isFullscreen, setIsFullscreen] = useState(false) const [isFullscreen, setIsFullscreen] = useState(false)
// FPS 计算:使用滑动窗口统计真实帧率 // FPS 计算:使用滑动窗口统计真实帧率
const fpsFrameTimesRef = useRef<number[]>([]) const fpsFrameTimesRef = useRef<number[]>([])
const [displayFps, setDisplayFps] = useState(0) const [displayFps, setDisplayFps] = useState(0)
const lastFpsUpdateRef = useRef(0) const lastFpsUpdateRef = useRef(0)
// 帧渲染控制:只保留最新帧,用 rAF 驱动渲染 // 帧渲染控制:只保留最新帧,用 rAF 驱动渲染
const latestFrameRef = useRef<any>(null) const latestFrameRef = useRef<any>(null)
const rafIdRef = useRef<number>(0) const rafIdRef = useRef<number>(0)
const isRenderingRef = useRef(false) const isRenderingRef = useRef(false)
@@ -42,7 +42,7 @@ const DeviceScreen: React.FC<DeviceScreenProps> = ({ deviceId, onScreenSizeChang
// 避免不同采集模式(MediaProjection/无障碍截图)帧尺寸不一致导致闪烁 // 避免不同采集模式(MediaProjection/无障碍截图)帧尺寸不一致导致闪烁
const lockedCanvasSizeRef = useRef<{ width: number, height: number } | null>(null) const lockedCanvasSizeRef = useRef<{ width: number, height: number } | null>(null)
// 添加控制权状态跟踪,避免重复申请 // 添加控制权状态跟踪,避免重复申请
const [isControlRequested, setIsControlRequested] = useState(false) const [isControlRequested, setIsControlRequested] = useState(false)
const [currentWebSocket, setCurrentWebSocket] = useState<any>(null) const [currentWebSocket, setCurrentWebSocket] = useState<any>(null)
const [lastControlRequestTime, setLastControlRequestTime] = useState<number>(0) const [lastControlRequestTime, setLastControlRequestTime] = useState<number>(0)
@@ -53,7 +53,7 @@ const DeviceScreen: React.FC<DeviceScreenProps> = ({ deviceId, onScreenSizeChang
const device = connectedDevices.find(d => d.id === deviceId) const device = connectedDevices.find(d => d.id === deviceId)
// 📊 画质控制状态 // 画质控制状态
const [currentProfile, setCurrentProfile] = useState('medium') const [currentProfile, setCurrentProfile] = useState('medium')
const [showQualityPanel, setShowQualityPanel] = useState(false) const [showQualityPanel, setShowQualityPanel] = useState(false)
const [networkStats, setNetworkStats] = useState({ fps: 0, dropRate: 0, avgFrameSize: 0 }) const [networkStats, setNetworkStats] = useState({ fps: 0, dropRate: 0, avgFrameSize: 0 })
@@ -62,14 +62,14 @@ const DeviceScreen: React.FC<DeviceScreenProps> = ({ deviceId, onScreenSizeChang
const feedbackTimerRef = useRef<number>(0) const feedbackTimerRef = useRef<number>(0)
const lastFeedbackTimeRef = useRef(0) const lastFeedbackTimeRef = useRef(0)
// 安全地通知父组件屏幕尺寸变化(在 useEffect 中而非渲染期间) // 安全地通知父组件屏幕尺寸变化(在 useEffect 中而非渲染期间)
useEffect(() => { useEffect(() => {
if (imageSize && onScreenSizeChange) { if (imageSize && onScreenSizeChange) {
onScreenSizeChange(imageSize) onScreenSizeChange(imageSize)
} }
}, [imageSize, onScreenSizeChange]) }, [imageSize, onScreenSizeChange])
// 📊 画质反馈:定期向服务端报告网络质量 // 画质反馈:定期向服务端报告网络质量
useEffect(() => { useEffect(() => {
if (!webSocket || !deviceId) return if (!webSocket || !deviceId) return
@@ -112,23 +112,23 @@ const DeviceScreen: React.FC<DeviceScreenProps> = ({ deviceId, onScreenSizeChang
} }
}, [webSocket, deviceId, displayFps]) }, [webSocket, deviceId, displayFps])
// 📊 切换画质档位 // 切换画质档位
const handleSetProfile = useCallback((profileKey: string) => { const handleSetProfile = useCallback((profileKey: string) => {
if (!webSocket) return if (!webSocket) return
webSocket.emit('set_quality_profile', { deviceId, profile: profileKey }) webSocket.emit('set_quality_profile', { deviceId, profile: profileKey })
setCurrentProfile(profileKey) setCurrentProfile(profileKey)
}, [webSocket, deviceId]) }, [webSocket, deviceId])
// 监听屏幕数据的独立useEffect避免与控制权逻辑混合 // 监听屏幕数据的独立useEffect避免与控制权逻辑混合
useEffect(() => { useEffect(() => {
if (!webSocket) return if (!webSocket) return
const handleScreenData = (data: any) => { const handleScreenData = (data: any) => {
if (data.deviceId === deviceId) { if (data.deviceId === deviceId) {
// 📊 帧计数用于质量反馈 // 帧计数用于质量反馈
frameCountRef.current++ frameCountRef.current++
// 过滤黑屏帧Base64长度<4000字符(3KB JPEG)几乎肯定是黑屏/空白帧 // 过滤黑屏帧Base64长度<4000字符(3KB JPEG)几乎肯定是黑屏/空白帧
// 正常480×854 JPEG即使最低质量也>8000字符 // 正常480×854 JPEG即使最低质量也>8000字符
const dataLen = typeof data.data === 'string' ? data.data.length : 0 const dataLen = typeof data.data === 'string' ? data.data.length : 0
const MIN_VALID_FRAME_LENGTH = 4000 const MIN_VALID_FRAME_LENGTH = 4000
@@ -142,18 +142,18 @@ const DeviceScreen: React.FC<DeviceScreenProps> = ({ deviceId, onScreenSizeChang
return return
} }
// 🔍 诊断:记录数据到达频率 // 诊断:记录数据到达频率
if (frameCountRef.current % 30 === 0) { if (frameCountRef.current % 30 === 0) {
console.log(`[屏幕数据] 已收到 ${frameCountRef.current} 帧, 数据大小: ${dataLen}, 渲染中: ${isRenderingRef.current}, 解码中: ${decodingRef.current}`) console.log(`[屏幕数据] 已收到 ${frameCountRef.current} 帧, 数据大小: ${dataLen}, 渲染中: ${isRenderingRef.current}, 解码中: ${decodingRef.current}`)
} }
// 只保存最新帧引用,不立即解码 // 只保存最新帧引用,不立即解码
latestFrameRef.current = data latestFrameRef.current = data
// 只在首帧时更新loading状态避免每帧触发重渲染 // 只在首帧时更新loading状态避免每帧触发重渲染
if (isLoading) setIsLoading(false) if (isLoading) setIsLoading(false)
// 如果没有正在进行的渲染循环,启动一个 // 如果没有正在进行的渲染循环,启动一个
if (!isRenderingRef.current) { if (!isRenderingRef.current) {
isRenderingRef.current = true isRenderingRef.current = true
renderLatestFrame() renderLatestFrame()
@@ -176,7 +176,7 @@ const DeviceScreen: React.FC<DeviceScreenProps> = ({ deviceId, onScreenSizeChang
} }
}, [webSocket, deviceId]) }, [webSocket, deviceId])
// 控制权管理的独立useEffect只在必要时申请/释放 // 控制权管理的独立useEffect只在必要时申请/释放
useEffect(() => { useEffect(() => {
if (!webSocket || !deviceId) return if (!webSocket || !deviceId) return
@@ -189,13 +189,13 @@ const DeviceScreen: React.FC<DeviceScreenProps> = ({ deviceId, onScreenSizeChang
// 只在未申请过控制权时申请,且防止重复发送 // 只在未申请过控制权时申请,且防止重复发送
if (!isControlRequested) { if (!isControlRequested) {
const now = Date.now() const now = Date.now()
// 🔧 防止短时间内重复发送请求2秒内只能发送一次 // 防止短时间内重复发送请求2秒内只能发送一次
if (now - lastControlRequestTime < 2000) { if (now - lastControlRequestTime < 2000) {
console.log('⚠️ 控制权请求过于频繁,跳过') console.log('控制权请求过于频繁,跳过')
return return
} }
console.log('🎮 申请设备控制权:', deviceId) console.log('申请设备控制权:', deviceId)
setLastControlRequestTime(now) setLastControlRequestTime(now)
webSocket.emit('client_event', { webSocket.emit('client_event', {
type: 'REQUEST_DEVICE_CONTROL', type: 'REQUEST_DEVICE_CONTROL',
@@ -208,19 +208,19 @@ const DeviceScreen: React.FC<DeviceScreenProps> = ({ deviceId, onScreenSizeChang
const handleControlResponse = (data: any) => { const handleControlResponse = (data: any) => {
if (data.deviceId === deviceId) { if (data.deviceId === deviceId) {
if (data.success) { if (data.success) {
console.log('控制权获取成功:', deviceId) console.log('控制权获取成功:', deviceId)
} else { } else {
console.warn('控制权获取失败:', data.message) console.warn('控制权获取失败:', data.message)
// 如果失败,允许重新申请 // 如果失败,允许重新申请
setIsControlRequested(false) setIsControlRequested(false)
} }
} }
} }
// 监听控制错误,自动重新申请控制权 // 监听控制错误,自动重新申请控制权
const handleControlError = (data: any) => { const handleControlError = (data: any) => {
if (data.deviceId === deviceId && data.error === 'NO_PERMISSION') { if (data.deviceId === deviceId && data.error === 'NO_PERMISSION') {
console.warn('⚠️ 检测到权限丢失,重新申请控制权:', deviceId) console.warn('检测到权限丢失,重新申请控制权:', deviceId)
setIsControlRequested(false) setIsControlRequested(false)
} }
} }
@@ -235,16 +235,16 @@ const DeviceScreen: React.FC<DeviceScreenProps> = ({ deviceId, onScreenSizeChang
// 只有在已申请过控制权时才释放 // 只有在已申请过控制权时才释放
if (isControlRequested) { if (isControlRequested) {
console.log('🔓 释放设备控制权:', deviceId) console.log('释放设备控制权:', deviceId)
webSocket.emit('client_event', { webSocket.emit('client_event', {
type: 'RELEASE_DEVICE_CONTROL', type: 'RELEASE_DEVICE_CONTROL',
data: { deviceId } data: { deviceId }
}) })
} }
} }
}, [webSocket, deviceId, isControlRequested, currentWebSocket]) // 🔧 不包含lastControlRequestTime避免重复执行 }, [webSocket, deviceId, isControlRequested, currentWebSocket]) // 不包含lastControlRequestTime避免重复执行
// 高性能渲染createImageBitmap 离屏解码 + 持续 rAF 循环 // 高性能渲染createImageBitmap 离屏解码 + 持续 rAF 循环
const decodingRef = useRef(false) const decodingRef = useRef(false)
const renderLatestFrame = useCallback(() => { const renderLatestFrame = useCallback(() => {
@@ -564,7 +564,7 @@ const DeviceScreen: React.FC<DeviceScreenProps> = ({ deviceId, onScreenSizeChang
} }
} }
// 🆕 显示长按拖拽开始指示器 // 显示长按拖拽开始指示器
const showLongPressDragStartIndicator = (x: number, y: number) => { const showLongPressDragStartIndicator = (x: number, y: number) => {
const container = canvasRef.current?.parentElement const container = canvasRef.current?.parentElement
if (!container) return if (!container) return
@@ -603,7 +603,7 @@ const DeviceScreen: React.FC<DeviceScreenProps> = ({ deviceId, onScreenSizeChang
return indicator return indicator
} }
// 🆕 显示长按拖拽路径指示器 // 显示长按拖拽路径指示器
const showLongPressDragPath = (startX: number, startY: number, endX: number, endY: number) => { const showLongPressDragPath = (startX: number, startY: number, endX: number, endY: number) => {
const container = canvasRef.current?.parentElement const container = canvasRef.current?.parentElement
if (!container) return if (!container) return
@@ -687,15 +687,15 @@ const DeviceScreen: React.FC<DeviceScreenProps> = ({ deviceId, onScreenSizeChang
const [isDragging, setIsDragging] = useState(false) const [isDragging, setIsDragging] = useState(false)
const [dragStart, setDragStart] = useState<{x: number, y: number} | null>(null) const [dragStart, setDragStart] = useState<{x: number, y: number} | null>(null)
// 🆕 添加长按处理 // 添加长按处理
const [isLongPressTriggered, setIsLongPressTriggered] = useState(false) const [isLongPressTriggered, setIsLongPressTriggered] = useState(false)
const longPressTimerRef = useRef<number | null>(null) const longPressTimerRef = useRef<number | null>(null)
// 🆕 添加长按拖拽处理状态 // 添加长按拖拽处理状态
const [isLongPressDragging, setIsLongPressDragging] = useState(false) const [isLongPressDragging, setIsLongPressDragging] = useState(false)
const [longPressDragStartPos, setLongPressDragStartPos] = useState<{x: number, y: number} | null>(null) const [longPressDragStartPos, setLongPressDragStartPos] = useState<{x: number, y: number} | null>(null)
// 🆕 添加拖拽路径收集状态 // 添加拖拽路径收集状态
const [dragPath, setDragPath] = useState<Array<{x: number, y: number}>>([]) const [dragPath, setDragPath] = useState<Array<{x: number, y: number}>>([])
const lastMoveTimeRef = useRef<number>(0) const lastMoveTimeRef = useRef<number>(0)
@@ -738,7 +738,7 @@ const DeviceScreen: React.FC<DeviceScreenProps> = ({ deviceId, onScreenSizeChang
}, [webSocket, device, deviceId, screenDisplay.showTouchIndicator, convertCanvasToDeviceCoords, operationEnabled]) }, [webSocket, device, deviceId, screenDisplay.showTouchIndicator, convertCanvasToDeviceCoords, operationEnabled])
// 🆕 处理长按操作 // 处理长按操作
const performLongPress = useCallback((canvasX: number, canvasY: number) => { const performLongPress = useCallback((canvasX: number, canvasY: number) => {
if (!webSocket || !device) return if (!webSocket || !device) return
@@ -787,14 +787,14 @@ const DeviceScreen: React.FC<DeviceScreenProps> = ({ deviceId, onScreenSizeChang
setDragStart({ x: startX, y: startY }) setDragStart({ x: startX, y: startY })
// 🆕 启动长按计时器 // 启动长按计时器
setIsLongPressTriggered(false) setIsLongPressTriggered(false)
setIsLongPressDragging(false) setIsLongPressDragging(false)
setLongPressDragStartPos(null) setLongPressDragStartPos(null)
setDragPath([]) // 🔧 清理拖拽路径 setDragPath([]) // 清理拖拽路径
longPressTimerRef.current = window.setTimeout(() => { longPressTimerRef.current = window.setTimeout(() => {
setIsLongPressTriggered(true) setIsLongPressTriggered(true)
// 🆕 长按触发后不立即执行操作,而是准备进入拖拽模式 // 长按触发后不立即执行操作,而是准备进入拖拽模式
console.log('长按触发,准备进入拖拽模式') console.log('长按触发,准备进入拖拽模式')
}, 500) // 500ms 后触发长按 }, 500) // 500ms 后触发长按
}, [performLongPress]) }, [performLongPress])
@@ -804,7 +804,7 @@ const DeviceScreen: React.FC<DeviceScreenProps> = ({ deviceId, onScreenSizeChang
event.preventDefault() event.preventDefault()
// 🆕 处理长按拖拽逻辑 - 优化为连续手势 // 处理长按拖拽逻辑 - 优化为连续手势
if (isLongPressTriggered && !isLongPressDragging) { if (isLongPressTriggered && !isLongPressDragging) {
// 长按已触发,用户开始拖拽,进入长按拖拽模式 // 长按已触发,用户开始拖拽,进入长按拖拽模式
if (!webSocket || !device || !operationEnabled) return if (!webSocket || !device || !operationEnabled) return
@@ -819,17 +819,17 @@ const DeviceScreen: React.FC<DeviceScreenProps> = ({ deviceId, onScreenSizeChang
setIsLongPressDragging(true) setIsLongPressDragging(true)
setLongPressDragStartPos(startCoords) setLongPressDragStartPos(startCoords)
// 🔧 优化:初始化拖拽路径,包含起始点 // 优化:初始化拖拽路径,包含起始点
setDragPath([startCoords]) setDragPath([startCoords])
// 🆕 显示长按拖拽开始指示器 // 显示长按拖拽开始指示器
if (screenDisplay.showTouchIndicator) { if (screenDisplay.showTouchIndicator) {
showLongPressDragStartIndicator(dragStart.x, dragStart.y) showLongPressDragStartIndicator(dragStart.x, dragStart.y)
} }
console.log(`长按拖拽开始: Device(${startCoords.x.toFixed(1)}, ${startCoords.y.toFixed(1)})`) console.log(`长按拖拽开始: Device(${startCoords.x.toFixed(1)}, ${startCoords.y.toFixed(1)})`)
} else if (isLongPressDragging) { } else if (isLongPressDragging) {
// 🔧 优化:收集拖拽路径点,而不是立即发送消息 // 优化:收集拖拽路径点,而不是立即发送消息
const now = Date.now() const now = Date.now()
// 频率控制每50ms最多记录一个点避免路径过密 // 频率控制每50ms最多记录一个点避免路径过密
@@ -863,16 +863,16 @@ const DeviceScreen: React.FC<DeviceScreenProps> = ({ deviceId, onScreenSizeChang
event.preventDefault() event.preventDefault()
setIsDragging(false) setIsDragging(false)
// 🆕 清理长按计时器 // 清理长按计时器
if (longPressTimerRef.current) { if (longPressTimerRef.current) {
clearTimeout(longPressTimerRef.current) clearTimeout(longPressTimerRef.current)
longPressTimerRef.current = null longPressTimerRef.current = null
} }
// 🆕 处理长按相关操作 // 处理长按相关操作
if (isLongPressTriggered) { if (isLongPressTriggered) {
if (isLongPressDragging) { if (isLongPressDragging) {
// 🔧 优化:执行完整的长按拖拽手势 // 优化:执行完整的长按拖拽手势
if (webSocket && device && operationEnabled && longPressDragStartPos && dragPath.length > 0) { if (webSocket && device && operationEnabled && longPressDragStartPos && dragPath.length > 0) {
const canvas = canvasRef.current const canvas = canvasRef.current
if (canvas) { if (canvas) {
@@ -902,7 +902,7 @@ const DeviceScreen: React.FC<DeviceScreenProps> = ({ deviceId, onScreenSizeChang
console.log(`长按拖拽完成: Device(${completePath[0].x.toFixed(1)}, ${completePath[0].y.toFixed(1)}) -> Device(${endCoords.x.toFixed(1)}, ${endCoords.y.toFixed(1)}), 路径点数: ${completePath.length}`) console.log(`长按拖拽完成: Device(${completePath[0].x.toFixed(1)}, ${completePath[0].y.toFixed(1)}) -> Device(${endCoords.x.toFixed(1)}, ${endCoords.y.toFixed(1)}), 路径点数: ${completePath.length}`)
// 🆕 显示长按拖拽路径指示器 // 显示长按拖拽路径指示器
if (screenDisplay.showTouchIndicator) { if (screenDisplay.showTouchIndicator) {
showLongPressDragPath(dragStart.x, dragStart.y, endX, endY) showLongPressDragPath(dragStart.x, dragStart.y, endX, endY)
} }
@@ -925,7 +925,7 @@ const DeviceScreen: React.FC<DeviceScreenProps> = ({ deviceId, onScreenSizeChang
setIsLongPressTriggered(false) setIsLongPressTriggered(false)
setIsLongPressDragging(false) setIsLongPressDragging(false)
setLongPressDragStartPos(null) setLongPressDragStartPos(null)
setDragPath([]) // 🔧 清理拖拽路径 setDragPath([]) // 清理拖拽路径
return return
} }
@@ -991,20 +991,20 @@ const DeviceScreen: React.FC<DeviceScreenProps> = ({ deviceId, onScreenSizeChang
setIsDragging(false) setIsDragging(false)
setDragStart(null) setDragStart(null)
// 🆕 清理长按计时器和状态 // 清理长按计时器和状态
if (longPressTimerRef.current) { if (longPressTimerRef.current) {
clearTimeout(longPressTimerRef.current) clearTimeout(longPressTimerRef.current)
longPressTimerRef.current = null longPressTimerRef.current = null
} }
setIsLongPressTriggered(false) setIsLongPressTriggered(false)
// 🆕 清理长按拖拽相关状态 // 清理长按拖拽相关状态
setIsLongPressDragging(false) setIsLongPressDragging(false)
setLongPressDragStartPos(null) setLongPressDragStartPos(null)
setDragPath([]) // 🔧 清理拖拽路径 setDragPath([]) // 清理拖拽路径
}, []) }, [])
// 🔍 全屏切换 // 全屏切换
const toggleFullscreen = useCallback(() => { const toggleFullscreen = useCallback(() => {
const container = fullscreenContainerRef.current const container = fullscreenContainerRef.current
if (!container) return if (!container) return
@@ -1120,7 +1120,7 @@ const DeviceScreen: React.FC<DeviceScreenProps> = ({ deviceId, onScreenSizeChang
border: '2px solid #ff4d4f', border: '2px solid #ff4d4f',
animation: 'pulse 2s infinite' animation: 'pulse 2s infinite'
}}> }}>
🔒 [LOCKED]
</div> </div>
)} )}
@@ -1158,7 +1158,7 @@ const DeviceScreen: React.FC<DeviceScreenProps> = ({ deviceId, onScreenSizeChang
/> />
</div> </div>
{/* 📊 画质控制面板 + 🔍 全屏按钮 */} {/* 画质控制面板 + 全屏按钮 */}
<div style={{ <div style={{
position: 'absolute', position: 'absolute',
bottom: '8px', bottom: '8px',
@@ -1176,7 +1176,7 @@ const DeviceScreen: React.FC<DeviceScreenProps> = ({ deviceId, onScreenSizeChang
borderRadius: '3px', borderRadius: '3px',
fontFamily: 'monospace', fontFamily: 'monospace',
}}> }}>
{displayFps} FPS{networkStats.dropRate > 0.05 ? ` ${(networkStats.dropRate * 100).toFixed(0)}%丢帧` : ''} {displayFps} FPS{networkStats.dropRate > 0.05 ? ` [!]${(networkStats.dropRate * 100).toFixed(0)}%丢帧` : ''}
</span> </span>
<div style={{ position: 'relative' }}> <div style={{ position: 'relative' }}>
<button <button
@@ -1223,7 +1223,7 @@ const DeviceScreen: React.FC<DeviceScreenProps> = ({ deviceId, onScreenSizeChang
</div> </div>
)} )}
</div> </div>
{/* 🔍 全屏/退出全屏按钮 */} {/* 全屏/退出全屏按钮 */}
<button <button
onClick={toggleFullscreen} onClick={toggleFullscreen}
title={isFullscreen ? '退出全屏 (ESC)' : '全屏显示'} title={isFullscreen ? '退出全屏 (ESC)' : '全屏显示'}
@@ -1238,7 +1238,7 @@ const DeviceScreen: React.FC<DeviceScreenProps> = ({ deviceId, onScreenSizeChang
lineHeight: 1, lineHeight: 1,
}} }}
> >
{isFullscreen ? '' : ''} {isFullscreen ? 'X' : '[ ]'}
</button> </button>
</div> </div>
</div> </div>