style: DeviceScreen.tsx清理全部emoji符号
- 移除注释中所有emoji标记(checkmark/new/wrench/search等) - 移除日志输出中的emoji(控制权/警告/错误等) - 移除UI文本中的emoji(操作已禁用/丢帧警告/全屏按钮) - 清理Vite缓存解决pendingSizeRef旧代码残留问题
This commit is contained in:
@@ -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>
|
||||||
|
|||||||
Reference in New Issue
Block a user