From 03e4cb8dabb4093893e3b659c9836984b270b862 Mon Sep 17 00:00:00 2001 From: wdvipa Date: Sun, 15 Feb 2026 19:45:58 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20Web=E7=AB=AF=E8=87=AA=E5=8A=A8=E5=88=B7?= =?UTF-8?q?=E6=96=B0=E7=94=BB=E9=9D=A2=E6=9C=BA=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - DeviceScreen添加无帧超时检测(8秒无帧触发刷新) - 自动发送REFRESH_SCREEN请求给服务端 - 15秒冷却期防止频繁刷新 --- node_modules/.vite/deps/_metadata.json | 24 +++++++------- src/components/Device/DeviceScreen.tsx | 43 ++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 12 deletions(-) diff --git a/node_modules/.vite/deps/_metadata.json b/node_modules/.vite/deps/_metadata.json index 6c57806..18c452f 100644 --- a/node_modules/.vite/deps/_metadata.json +++ b/node_modules/.vite/deps/_metadata.json @@ -7,73 +7,73 @@ "react": { "src": "../../react/index.js", "file": "react.js", - "fileHash": "82b88bac", + "fileHash": "b64083dc", "needsInterop": true }, "react-dom": { "src": "../../react-dom/index.js", "file": "react-dom.js", - "fileHash": "f147bcf0", + "fileHash": "4cc1d72b", "needsInterop": true }, "@reduxjs/toolkit": { "src": "../../@reduxjs/toolkit/dist/redux-toolkit.modern.mjs", "file": "@reduxjs_toolkit.js", - "fileHash": "e2e532ed", + "fileHash": "229d524d", "needsInterop": false }, "react-redux": { "src": "../../react-redux/dist/react-redux.mjs", "file": "react-redux.js", - "fileHash": "49e0dcfd", + "fileHash": "9cd5b390", "needsInterop": false }, "antd": { "src": "../../antd/es/index.js", "file": "antd.js", - "fileHash": "1c827006", + "fileHash": "804ee91a", "needsInterop": false }, "socket.io-client": { "src": "../../socket.io-client/build/esm/index.js", "file": "socket__io-client.js", - "fileHash": "f1f126a4", + "fileHash": "dfecfa57", "needsInterop": false }, "react/jsx-dev-runtime": { "src": "../../react/jsx-dev-runtime.js", "file": "react_jsx-dev-runtime.js", - "fileHash": "92554eaf", + "fileHash": "ee0e2149", "needsInterop": true }, "react/jsx-runtime": { "src": "../../react/jsx-runtime.js", "file": "react_jsx-runtime.js", - "fileHash": "c9146743", + "fileHash": "a8d2b404", "needsInterop": true }, "@ant-design/icons": { "src": "../../@ant-design/icons/es/index.js", "file": "@ant-design_icons.js", - "fileHash": "5c57aafc", + "fileHash": "02740ed7", "needsInterop": false }, "antd/locale/zh_CN": { "src": "../../antd/locale/zh_CN.js", "file": "antd_locale_zh_CN.js", - "fileHash": "731388b8", + "fileHash": "5fab095f", "needsInterop": true }, "dayjs": { "src": "../../dayjs/dayjs.min.js", "file": "dayjs.js", - "fileHash": "581df681", + "fileHash": "ed91b429", "needsInterop": true }, "react-dom/client": { "src": "../../react-dom/client.js", "file": "react-dom_client.js", - "fileHash": "f34fbc85", + "fileHash": "1733c935", "needsInterop": true } }, diff --git a/src/components/Device/DeviceScreen.tsx b/src/components/Device/DeviceScreen.tsx index 287af65..e2bf319 100644 --- a/src/components/Device/DeviceScreen.tsx +++ b/src/components/Device/DeviceScreen.tsx @@ -176,6 +176,49 @@ const DeviceScreen: React.FC = ({ deviceId, onScreenSizeChang } }, [webSocket, deviceId]) + // Auto-refresh: detect no-frame timeout and request screen refresh from device + const lastFrameTimeRef = useRef(Date.now()) + const refreshRequestedRef = useRef(false) + const NO_FRAME_TIMEOUT = 8000 // 8 seconds without frames triggers refresh + const REFRESH_COOLDOWN = 15000 // minimum 15 seconds between refresh requests + + // Update last frame time when screen_data arrives + useEffect(() => { + if (!webSocket || !deviceId) return + + const trackFrameTime = (data: any) => { + if (data.deviceId === deviceId) { + lastFrameTimeRef.current = Date.now() + refreshRequestedRef.current = false + } + } + + webSocket.on('screen_data', trackFrameTime) + return () => { webSocket.off('screen_data', trackFrameTime) } + }, [webSocket, deviceId]) + + // Periodic check for frame timeout + useEffect(() => { + if (!webSocket || !deviceId) return + + const checkInterval = window.setInterval(() => { + const elapsed = Date.now() - lastFrameTimeRef.current + if (elapsed < NO_FRAME_TIMEOUT) return + if (refreshRequestedRef.current) return + + console.log(`[AutoRefresh] No frames for ${Math.round(elapsed / 1000)}s, requesting screen refresh`) + refreshRequestedRef.current = true + lastFrameTimeRef.current = Date.now() - NO_FRAME_TIMEOUT + REFRESH_COOLDOWN + + webSocket.emit('client_event', { + type: 'REFRESH_SCREEN', + data: { deviceId } + }) + }, 3000) // check every 3 seconds + + return () => { clearInterval(checkInterval) } + }, [webSocket, deviceId]) + // 控制权管理的独立useEffect,只在必要时申请/释放 useEffect(() => { if (!webSocket || !deviceId) return