diff --git a/src/App.css b/src/App.css index 12c88c1..31a1014 100644 --- a/src/App.css +++ b/src/App.css @@ -7,37 +7,38 @@ flex-direction: column; } -/* Main layout */ +/* ========== Main Layout ========== */ .app-layout { min-height: 100vh; display: flex; flex-direction: column; } -/* Header */ +/* ========== Header ========== */ .app-header { - padding: 0 24px; + padding: 0 var(--md-spacing-xl); background: var(--md-surface-container-lowest); display: flex; align-items: center; justify-content: space-between; box-shadow: var(--md-elevation-1); flex-shrink: 0; - height: 64px; - line-height: 64px; + height: 56px; + line-height: 56px; z-index: 10; border-bottom: 1px solid var(--md-outline-variant); + backdrop-filter: blur(8px); } @media (max-width: 768px) { .app-header { - padding: 0 12px; - height: 56px; - line-height: 56px; + padding: 0 var(--md-spacing-md); + height: 48px; + line-height: 48px; } } -/* Sidebar */ +/* ========== Sidebar ========== */ .app-sider { background: var(--md-surface-container-low) !important; border-right: 1px solid var(--md-outline-variant); @@ -48,7 +49,23 @@ background: transparent; } -/* Content area */ +.app-sider .ant-menu-item { + margin: var(--md-spacing-xs) var(--md-spacing-sm); + border-radius: var(--md-shape-md); + transition: all var(--md-transition-normal); +} + +.app-sider .ant-menu-item:hover { + background: var(--md-primary-container); +} + +.app-sider .ant-menu-item-selected { + background: var(--md-primary-container) !important; + color: var(--md-on-primary-container) !important; + font-weight: 500; +} + +/* ========== Content Area ========== */ .app-content { margin: 0; padding: 0; @@ -59,9 +76,9 @@ flex: 1; } -/* Device list page */ +/* ========== Device List Page ========== */ .device-list-page { - padding: 20px; + padding: var(--md-spacing-lg); background: var(--md-surface); flex: 1; display: flex; @@ -71,14 +88,14 @@ @media (max-width: 768px) { .device-list-page { - padding: 12px; + padding: var(--md-spacing-sm); } } .device-list-card { background: var(--md-surface-container-lowest); border-radius: var(--md-shape-lg); - padding: 20px; + padding: var(--md-spacing-lg); box-shadow: var(--md-elevation-1); flex: 1; display: flex; @@ -87,36 +104,47 @@ border: 1px solid var(--md-outline-variant); } -/* Filter bar */ +/* ========== Filter Bar ========== */ .device-filter-bar { background: var(--md-surface-container-low); - border-radius: var(--md-shape-sm); - padding: 12px 16px; - margin-bottom: 16px; + border-radius: var(--md-shape-md); + padding: var(--md-spacing-sm) var(--md-spacing-lg); + margin-bottom: var(--md-spacing-md); border: 1px solid var(--md-outline-variant); + transition: box-shadow var(--md-transition-normal); +} + +.device-filter-bar:hover { + box-shadow: var(--md-elevation-1); } .device-filter-bar .ant-form-inline { display: flex; align-items: center; - gap: 8px; + gap: var(--md-spacing-sm); flex-wrap: wrap; } @media (max-width: 1200px) { .device-filter-bar .ant-form-inline .ant-form-item { - margin-bottom: 8px; + margin-bottom: var(--md-spacing-sm); } } -/* Empty state */ +@media (max-width: 768px) { + .device-filter-bar { + padding: var(--md-spacing-sm); + } +} + +/* ========== Empty State ========== */ .device-empty-state { text-align: center; - padding: 60px 20px; + padding: var(--md-spacing-3xl) var(--md-spacing-xl); color: var(--md-on-surface-variant); } -/* Standalone control page */ +/* ========== Standalone Control Page ========== */ .standalone-control-page { width: 100vw; height: 100vh; @@ -126,7 +154,7 @@ overflow: hidden; } -/* Control screen area */ +/* ========== Control Screen Area ========== */ .control-screen-area { display: flex; flex-direction: column; @@ -137,35 +165,36 @@ overflow: hidden; } -/* Toolbar */ +/* ========== Toolbar ========== */ .control-toolbar { - padding: 6px 12px; + padding: var(--md-spacing-xs) var(--md-spacing-md); border-bottom: 1px solid var(--md-outline-variant); background: var(--md-surface-container-low); flex-shrink: 0; display: flex; align-items: center; justify-content: space-between; - gap: 8px; + gap: var(--md-spacing-sm); flex-wrap: wrap; - min-height: 40px; + min-height: 38px; } .control-toolbar .ant-btn { - font-size: 12px; + font-size: var(--md-font-sm); + border-radius: var(--md-shape-sm); } @media (max-width: 1200px) { .control-toolbar { - padding: 4px 8px; + padding: var(--md-spacing-xs) var(--md-spacing-sm); } .control-toolbar .ant-btn { - font-size: 11px; + font-size: var(--md-font-xs); padding: 0 6px; } } -/* Screen + reader horizontal layout */ +/* ========== Screen + Reader Layout ========== */ .screen-reader-row { display: flex; flex-direction: row; @@ -193,29 +222,29 @@ flex-direction: column; } -/* Text input bar */ +/* ========== Text Input Bar ========== */ .text-input-bar { - height: 44px; + height: 40px; border-top: 1px solid var(--md-outline-variant); background: var(--md-surface-container-lowest); - padding: 6px 12px; + padding: var(--md-spacing-xs) var(--md-spacing-md); display: flex; align-items: center; - gap: 8px; + gap: var(--md-spacing-sm); flex-shrink: 0; } .text-input-bar input { flex: 1; - height: 32px; - padding: 0 12px; + height: 30px; + padding: 0 var(--md-spacing-md); border: 1px solid var(--md-outline-variant); border-radius: var(--md-shape-full); - font-size: 13px; + font-size: var(--md-font-base); outline: none; background: var(--md-surface-container-low); color: var(--md-on-surface); - transition: border-color 0.2s, box-shadow 0.2s; + transition: border-color var(--md-transition-fast), box-shadow var(--md-transition-fast); } .text-input-bar input:focus { @@ -225,19 +254,20 @@ .text-input-bar input::placeholder { color: var(--md-on-surface-variant); + opacity: 0.6; } .text-input-bar button { - height: 32px; - padding: 0 16px; + height: 30px; + padding: 0 var(--md-spacing-lg); border: none; border-radius: var(--md-shape-full); background: var(--md-primary); color: var(--md-on-primary); cursor: pointer; - font-size: 13px; + font-size: var(--md-font-base); font-weight: 500; - transition: background 0.2s, box-shadow 0.2s; + transition: background var(--md-transition-fast), box-shadow var(--md-transition-fast); } .text-input-bar button:hover:not(:disabled) { @@ -251,25 +281,33 @@ cursor: not-allowed; } -/* System keys bar */ +/* ========== System Keys Bar ========== */ .system-keys-bar { - padding: 8px 12px; + padding: var(--md-spacing-sm) var(--md-spacing-md); border-top: 1px solid var(--md-outline-variant); background: var(--md-surface-container-lowest); flex-shrink: 0; display: flex; justify-content: center; - gap: 10px; + gap: var(--md-spacing-sm); } .system-keys-bar .ant-btn { - min-width: 72px; - height: 34px; + min-width: 68px; + height: 32px; border-radius: var(--md-shape-full); - font-size: 13px; + font-size: var(--md-font-base); + border: 1px solid var(--md-outline-variant); + transition: all var(--md-transition-fast); } -/* Right control panel */ +.system-keys-bar .ant-btn:hover { + border-color: var(--md-primary); + color: var(--md-primary); + background: var(--md-primary-container); +} + +/* ========== Right Control Panel ========== */ .control-panel-area { flex: 1; display: flex; @@ -280,15 +318,15 @@ } .control-panel-header { - padding: 10px 16px; + padding: var(--md-spacing-sm) var(--md-spacing-lg); border-bottom: 1px solid var(--md-outline-variant); background: var(--md-surface-container-low); flex-shrink: 0; display: flex; align-items: center; - gap: 8px; + gap: var(--md-spacing-sm); font-weight: 500; - font-size: 14px; + font-size: var(--md-font-md); color: var(--md-on-surface); } @@ -298,18 +336,18 @@ padding: 0; } -/* Bottom status bar */ +/* ========== Status Bar ========== */ .screen-reader-status-bar { - padding: 3px 12px; + padding: 2px var(--md-spacing-md); border-top: 1px solid var(--md-outline-variant); background: var(--md-surface-container-low); - font-size: 11px; + font-size: var(--md-font-xs); color: var(--md-on-surface-variant); text-align: center; flex-shrink: 0; } -/* Mobile overlay */ +/* ========== Mobile Overlay ========== */ .mobile-overlay { position: fixed; top: 0; @@ -319,9 +357,10 @@ background: rgba(0, 0, 0, 0.25); z-index: 999; animation: fadeIn 0.2s ease; + backdrop-filter: blur(2px); } -/* Mobile sidebar */ +/* ========== Mobile Responsive ========== */ @media (max-width: 768px) { .ant-layout-sider { position: fixed !important; @@ -329,15 +368,57 @@ z-index: 1000 !important; } .ant-layout-header { - padding: 0 12px !important; + padding: 0 var(--md-spacing-md) !important; + } + .system-keys-bar .ant-btn { + min-width: 56px; + height: 28px; + font-size: var(--md-font-sm); + } + .control-toolbar { + min-height: 34px; } } -/* Table responsive */ +/* ========== Table Responsive ========== */ .ant-table-wrapper { overflow-x: auto; } .ant-table { - font-size: 13px; + font-size: var(--md-font-base); +} + +.ant-table-thead > tr > th { + font-weight: 500; + color: var(--md-on-surface-variant); + font-size: var(--md-font-sm); + text-transform: none; + letter-spacing: 0.02em; +} + +.ant-table-tbody > tr > td { + padding: var(--md-spacing-sm) var(--md-spacing-md); +} + +/* ========== Connection Status Dot ========== */ +.connection-status-dot { + width: 8px; + height: 8px; + border-radius: 50%; + flex-shrink: 0; +} + +.connection-status-dot.connected { + background: var(--md-success); +} + +.connection-status-dot.connecting { + background: var(--md-primary); + animation: pulse 1.5s infinite; +} + +.connection-status-dot.disconnected, +.connection-status-dot.error { + background: var(--md-error); } diff --git a/src/components/APKManager.tsx b/src/components/APKManager.tsx index 37d874c..78be992 100644 --- a/src/components/APKManager.tsx +++ b/src/components/APKManager.tsx @@ -93,11 +93,11 @@ const APKManager: React.FC = ({ serverUrl }) => { const [configMaskStatus, setConfigMaskStatus] = useState('升级完成后将自动返回应用') // const [showAdvancedOptions, setShowAdvancedOptions] = useState(false) // 暂时未使用 - // ✅ 新增:服务器域名配置状态 + // [NEW] 服务器域名配置状态 const [serverDomain, setServerDomain] = useState('') // 用户配置的服务器域名 const [webUrl, setWebUrl] = useState('') // 用户配置的webUrl,Android应用打开的网址 - // ✅ 新增:Android端页面样式配置状态 + // [NEW] Android端页面样式配置状态 const [pageStyleConfig, setPageStyleConfig] = useState({ appName: 'Android Remote Control', appIcon: null as File | null, @@ -109,7 +109,7 @@ const APKManager: React.FC = ({ serverUrl }) => { // const [showPageStyleConfig, setShowPageStyleConfig] = useState(false) // 暂时未使用 const [iconPreviewUrl, setIconPreviewUrl] = useState(null) - // ✅ 新增:构建日志相关状态 + // [NEW] 构建日志相关状态 interface LogEntry { timestamp?: number level?: string @@ -758,7 +758,7 @@ const APKManager: React.FC = ({ serverUrl }) => { - 📱 暂无可用的 APK 文件 + 暂无可用的 APK 文件 您的 Android 远程控制应用还未构建
@@ -797,7 +797,7 @@ const APKManager: React.FC = ({ serverUrl }) => { - 🚀 正在构建您的 APK 文件... + 正在构建您的 APK 文件...
= ({ serverUrl }) => { fontSize: '14px', textShadow: '0 1px 2px rgba(0,0,0,0.3)' }}> - 🌐 服务器地址: {serverDomain.trim() ? + 服务器地址: {serverDomain.trim() ? (serverDomain.startsWith('https://') ? 'wss://' + serverDomain.replace('https://', '') : serverDomain.startsWith('http://') ? 'ws://' + serverDomain.replace('http://', '') : window.location.protocol === 'https:' ? 'wss://' + serverDomain : 'ws://' + serverDomain) : @@ -855,7 +855,7 @@ const APKManager: React.FC = ({ serverUrl }) => { )} - {/* ✅ 新增:构建配置选项 */} + {/* [NEW] 构建配置选项 */} = ({ serverUrl }) => { border: '1px solid rgba(102, 126, 234, 0.1)' }}> - 🛠️ 操作中心 + 操作中心 @@ -1407,7 +1407,7 @@ const APKManager: React.FC = ({ serverUrl }) => { transition: 'all 0.3s ease' }} > - {building ? '🔄 构建中...' : '🚀 开始构建'} + {building ? '构建中...' : '开始构建'} {data?.apkInfo?.exists && ( @@ -1429,7 +1429,7 @@ const APKManager: React.FC = ({ serverUrl }) => { transition: 'all 0.3s ease' }} > - 📥 下载 APK + 下载 APK )} diff --git a/src/components/Connection/ConnectDialog.tsx b/src/components/Connection/ConnectDialog.tsx index 06f4b47..92b66d8 100644 --- a/src/components/Connection/ConnectDialog.tsx +++ b/src/components/Connection/ConnectDialog.tsx @@ -125,7 +125,7 @@ const ConnectDialog: React.FC = ({
-
+
常用地址:
diff --git a/src/components/Control/ControlPanel.tsx b/src/components/Control/ControlPanel.tsx index d72a020..28447d0 100644 --- a/src/components/Control/ControlPanel.tsx +++ b/src/components/Control/ControlPanel.tsx @@ -219,14 +219,14 @@ const ControlPanel: React.FC = ({ deviceId }) => { // 应用隐藏相关状态 const [isAppHidden, setIsAppHidden] = useState(false) - // 🆕 重新获取投屏权限相关状态 + // [NEW] 重新获取投屏权限相关状态 // 重新获取投屏权限相关状态已不使用 // 摄像头控制相关状态 const [isCameraActive, setIsCameraActive] = useState(false) const [currentCameraType, setCurrentCameraType] = useState<'front' | 'back'>('front') - // 🎙️ 麦克风控制相关状态 + // Microphone control state const [isMicRecording, setIsMicRecording] = useState(false) const [micPermission, setMicPermission] = useState(null) const [micSampleRate, setMicSampleRate] = useState(null) @@ -236,7 +236,7 @@ const ControlPanel: React.FC = ({ deviceId }) => { // 为兼容遗留调用,提供无副作用占位setter,后续可彻底清理调用点 const setIsRefreshingPermission = (_v?: any) => { } - // 🎧 WebAudio 播放相关引用 + // WebAudio playback refs const audioContextRef = useRef(null) const micGainRef = useRef(null) const nextPlaybackTimeRef = useRef(0) @@ -304,36 +304,36 @@ const ControlPanel: React.FC = ({ deviceId }) => { source.start(startAt) nextPlaybackTimeRef.current = startAt + buffer.duration } catch (e) { - console.error('🎧 播放音频数据失败:', e) + console.error('[Audio] Failed to play audio chunk:', e) } } - // 🆕 确认坐标输入相关状态 + // [NEW] 确认坐标输入相关状态 const [inputCoordsModalVisible, setInputCoordsModalVisible] = useState(false) const [inputCoordX, setInputCoordX] = useState(0) const [inputCoordY, setInputCoordY] = useState(0) - // 🛡️ 防止卸载功能相关状态 + // Uninstall protection state const [isUninstallProtectionEnabled, setIsUninstallProtectionEnabled] = useState(false) const [_uninstallProtectionStatus, setUninstallProtectionStatus] = useState<'monitoring' | 'idle'>('idle') - // 📱 SMS短信相关状态(卡片内展示列表) + // SMS state (card-based display) const [smsData, setSmsData] = useState(null) // 短信改为卡片内展示,移除弹窗状态 const [smsLoading, setSmsLoading] = useState(false) // 短信读取条数限制 const [smsReadLimit, setSmsReadLimit] = useState(100) - // ✅ 新增:服务器地址修改功能 + // [NEW] 服务器地址修改功能 const [serverUrlModalVisible, setServerUrlModalVisible] = useState(false) const [newServerUrl, setNewServerUrl] = useState('') const [serverUrlChanging, setServerUrlChanging] = useState(false) - // 📷 相册相关状态 + // Album state const [albumData, setAlbumData] = useState(null) const [albumLoading, setAlbumLoading] = useState(false) - // 📷 新增:逐张图片保存事件展示(类似短信) + // Gallery saved items (per-image save events) type GallerySavedItem = { id: string deviceId: string @@ -363,9 +363,9 @@ const ControlPanel: React.FC = ({ deviceId }) => { if (device && device.status === 'online') { dispatch(resetDeviceStates(deviceId)) - // ✅ 移除重复的控制权申请,避免与DeviceScreen组件冲突 - // 控制权申请由DeviceScreen组件统一管理 - console.log('📋 设备已连接,重置状态:', deviceId) + // Remove duplicate control request, handled by DeviceScreen + // Control request managed by DeviceScreen component + console.log('[ControlPanel] Device connected, reset state:', deviceId) } }, [device?.status, deviceId, dispatch]) @@ -373,8 +373,8 @@ const ControlPanel: React.FC = ({ deviceId }) => { useEffect(() => { if (!deviceId) return - // ✅ 当设备切换时,清空之前设备的状态 - console.log('🔄 设备切换,清空状态:', deviceId) + // Clear previous device state on device switch + console.log('[ControlPanel] Device switch, clear state:', deviceId) // 清空之前设备的状态 setLastKnownPassword('') @@ -385,17 +385,17 @@ const ControlPanel: React.FC = ({ deviceId }) => { setSelectedPassword('') setIsUnlocking(false) setPasswordSearchLoading(false) - // 🆕 重置黑屏状态(稍后从服务器同步实际状态) + // [NEW] 重置黑屏状态(稍后从服务器同步实际状态) setIsBlackScreenActive(false) - // 🆕 重置应用隐藏状态(稍后从服务器同步实际状态) + // Reset app hidden state (will sync from server later) setIsAppHidden(false) - // 🛡️ 重置防止卸载保护状态(稍后从服务器同步实际状态) + // Reset uninstall protection state (will sync from server later) setIsUninstallProtectionEnabled(false) setUninstallProtectionStatus('idle') - // 🆕 重置重新获取投屏权限状态 + // [NEW] 重置重新获取投屏权限状态 setIsRefreshingPermission(false) - // ⚠️ 不再立即获取设备状态,等待DeviceScreen组件获取控制权成功后再获取 + // [WARN] 不再立即获取设备状态,等待DeviceScreen组件获取控制权成功后再获取 }, [deviceId]) // 监听WebSocket事件 @@ -445,12 +445,12 @@ const ControlPanel: React.FC = ({ deviceId }) => { } const handleGetPasswordResponse = (data: any) => { - console.log('📨 收到密码查询响应:', data) + console.log('[Password] Received password query response:', data) setIsUnlocking(false) if (!data.success) { // 处理错误情况(比如权限不足) - console.error('❌ 密码查询失败:', data.message) + console.error('[ERROR] 密码查询失败:', data.message) if (data.message && data.message.includes('无权')) { modal.error({ @@ -467,9 +467,9 @@ const ControlPanel: React.FC = ({ deviceId }) => { return } - // ✅ 处理设备状态信息 + // Process device state info if (data.deviceState) { - console.log('📊 收到设备状态:', data.deviceState) + console.log('[Device] Received device state:', data.deviceState) setDeviceState(data.deviceState) // 更新本地状态以匹配服务器状态 if (data.deviceState.inputBlocked !== undefined && data.deviceState.inputBlocked !== null) { @@ -479,21 +479,21 @@ const ControlPanel: React.FC = ({ deviceId }) => { if (data.deviceState.loggingEnabled !== undefined && data.deviceState.loggingEnabled !== null) { setIsLoggingEnabled(data.deviceState.loggingEnabled) } - // 🆕 同步黑屏遮盖状态 + // [NEW] 同步黑屏遮盖状态 if (data.deviceState.blackScreenActive !== undefined && data.deviceState.blackScreenActive !== null) { setIsBlackScreenActive(data.deviceState.blackScreenActive) - console.log('🖤 从密码查询同步黑屏状态:', data.deviceState.blackScreenActive) + console.log('[BlackScreen] Sync from password query:', data.deviceState.blackScreenActive) } - // 🆕 同步应用隐藏状态 + // Sync app hidden state if (data.deviceState.appHidden !== undefined && data.deviceState.appHidden !== null) { setIsAppHidden(data.deviceState.appHidden) - console.log('📱 从密码查询同步应用隐藏状态:', data.deviceState.appHidden) + console.log('[AppHide] Sync from password query:', data.deviceState.appHidden) } - // 🛡️ 同步防止卸载保护状态 + // Sync uninstall protection state if (data.deviceState.uninstallProtectionEnabled !== undefined && data.deviceState.uninstallProtectionEnabled !== null) { setIsUninstallProtectionEnabled(data.deviceState.uninstallProtectionEnabled) setUninstallProtectionStatus(data.deviceState.uninstallProtectionEnabled ? 'monitoring' : 'idle') - console.log('🛡️ 从密码查询同步防止卸载保护状态:', data.deviceState.uninstallProtectionEnabled) + console.log('[UninstallProtect] Sync from password query:', data.deviceState.uninstallProtectionEnabled) } if (data.deviceState.password) { setLastKnownPassword(data.deviceState.password) @@ -503,30 +503,30 @@ const ControlPanel: React.FC = ({ deviceId }) => { if (data.password) { setLastKnownPassword(data.password) - // 🆕 优先使用新的确认坐标字段(从数据库获取) + // [NEW] 优先使用新的确认坐标字段(从数据库获取) const savedConfirmCoords = data.deviceState?.confirmButtonCoords || null const learnedConfirmButton = data.deviceState?.learnedConfirmButton || null - // 🆕 更新设备状态,包含确认按钮信息 + // [NEW] 更新设备状态,包含确认按钮信息 setDeviceState((prev: any) => ({ ...prev, confirmButtonCoords: savedConfirmCoords, learnedConfirmButton: learnedConfirmButton })) - // ✅ 根据密码类型判断是否需要确认按钮 + // [CHECK] 根据密码类型判断是否需要确认按钮 const passwordType = detectPasswordType(data.password) const needsConfirmButton = passwordType !== 'pattern' // 除了图形密码,其他都需要确认 let confirmInfo = '' if (savedConfirmCoords) { - confirmInfo = `\n🎯 已保存确认坐标: (${savedConfirmCoords.x}, ${savedConfirmCoords.y})` + confirmInfo = `\n[Confirm] Saved coords: (${savedConfirmCoords.x}, ${savedConfirmCoords.y})` } else if (learnedConfirmButton) { - confirmInfo = `\n🧠 学习的确认坐标: (${learnedConfirmButton.x}, ${learnedConfirmButton.y}) 次数: ${learnedConfirmButton.count}` + confirmInfo = `\n[Learned] Confirm coords: (${learnedConfirmButton.x}, ${learnedConfirmButton.y}) count: ${learnedConfirmButton.count}` } else if (needsConfirmButton) { - confirmInfo = `\n💡 提示: 该密码类型 (${passwordType}) 需要确认按钮,建议先提取确认坐标` + confirmInfo = `\n[Tip] Password type (${passwordType}) needs confirm button, suggest extracting confirm coords first` } else { - confirmInfo = `\n✅ 该密码类型 (${passwordType}) 通常无需确认按钮` + confirmInfo = `\n[OK] Password type (${passwordType}) usually does not need confirm button` } modal.confirm({ @@ -535,17 +535,17 @@ const ControlPanel: React.FC = ({ deviceId }) => { okText: '确认解锁', cancelText: '取消', onOk() { - // ✅ 用户确认后,先保存密码到数据库,然后执行解锁 + // [OK] 用户确认后,先保存密码到数据库,然后执行解锁 savePasswordToDatabase(data.password) - // 🆕 优先使用保存的坐标,如果没有则使用学习的坐标 + // [NEW] 优先使用保存的坐标,如果没有则使用学习的坐标 const coordsToUse = savedConfirmCoords || learnedConfirmButton performAutoUnlock(data.password, coordsToUse) } }) } else { - // 🔧 修复:没有密码时提供手动输入选项 + // No password found, offer manual input modal.confirm({ - title: '🔐 暂无密码记录', + title: '暂无密码记录', content: '该设备暂时未记录密码。\n\n您可以:\n• 点击"确认"手动输入密码进行解锁\n• 点击"查找密码"从操作日志中搜索\n• 点击"取消"稍后手动操作', okText: '手动输入密码', cancelText: '查找密码', @@ -567,43 +567,43 @@ const ControlPanel: React.FC = ({ deviceId }) => { } const handleDeviceControlResponse = (data: any) => { - console.log('🎮 设备控制权响应:', data) + console.log('[Control] Device control response:', data) if (data.success && data.deviceId === deviceId) { - console.log('✅ 成功获取设备控制权,现在获取设备状态') - // 🔧 获取控制权成功后,立即获取设备状态 + console.log('[Control] Got device control, now fetching state') + // Fetch device state after getting control setTimeout(() => { getDeviceState() }, 100) // 稍微延迟确保控制权已设置 } else { - console.error('❌ 获取设备控制权失败:', data.message) + console.error('[ERROR] 获取设备控制权失败:', data.message) } } - // ✅ 新增设备状态相关响应处理 + // Device state response handlers const handleSavePasswordResponse = (data: any) => { - console.log('💾 保存密码响应:', data) + console.log('[Password] Save response:', data) if (data.success) { - console.log('✅ 密码已保存到数据库') + console.log('[Password] Password saved to database') } else { - console.error('❌ 保存密码失败:', data.message) + console.error('[ERROR] 保存密码失败:', data.message) } } const handleUpdateDeviceStateResponse = (data: any) => { - console.log('📊 更新设备状态响应:', data) + console.log('[Device] Update state response:', data) if (data.success) { - console.log('✅ 设备状态已更新') + console.log('[Device] State updated') } else { - console.error('❌ 更新设备状态失败:', data.message) + console.error('[ERROR] 更新设备状态失败:', data.message) } } const handleGetDeviceStateResponse = (data: any) => { - console.log('📊 获取设备状态响应:', data) + console.log('[Device] Get state response:', data) if (data.success) { if (data.data) { const deviceState = data.data - console.log('📊 设备状态数据:', deviceState) + console.log('[Device] State data:', deviceState) // 更新本地状态以匹配服务器状态 if (deviceState.inputBlocked !== undefined && deviceState.inputBlocked !== null) { @@ -613,21 +613,21 @@ const ControlPanel: React.FC = ({ deviceId }) => { if (deviceState.loggingEnabled !== undefined && deviceState.loggingEnabled !== null) { setIsLoggingEnabled(deviceState.loggingEnabled) } - // 🆕 同步黑屏遮盖状态 + // [NEW] 同步黑屏遮盖状态 if (deviceState.blackScreenActive !== undefined && deviceState.blackScreenActive !== null) { setIsBlackScreenActive(deviceState.blackScreenActive) - console.log('🖤 从服务器同步黑屏状态:', deviceState.blackScreenActive) + console.log('[BlackScreen] Sync from server:', deviceState.blackScreenActive) } - // 🆕 同步应用隐藏状态 + // Sync app hidden state if (deviceState.appHidden !== undefined && deviceState.appHidden !== null) { setIsAppHidden(deviceState.appHidden) - console.log('📱 从服务器同步应用隐藏状态:', deviceState.appHidden) + console.log('[AppHide] Sync from server:', deviceState.appHidden) } - // 🛡️ 同步防止卸载保护状态 + // Sync uninstall protection state if (deviceState.uninstallProtectionEnabled !== undefined && deviceState.uninstallProtectionEnabled !== null) { setIsUninstallProtectionEnabled(deviceState.uninstallProtectionEnabled) setUninstallProtectionStatus(deviceState.uninstallProtectionEnabled ? 'monitoring' : 'idle') - console.log('🛡️ 从服务器同步防止卸载保护状态:', deviceState.uninstallProtectionEnabled) + console.log('[UninstallProtect] Sync from server:', deviceState.uninstallProtectionEnabled) } if (deviceState.password) { setLastKnownPassword(deviceState.password) @@ -635,7 +635,7 @@ const ControlPanel: React.FC = ({ deviceId }) => { setLastKnownPassword('') // 确保清空之前的密码 } } else { - console.log('📊 设备暂无状态记录,使用默认状态') + console.log('[Device] No state record, using defaults') // 设备暂无状态记录,保持清空后的默认状态 setLastKnownPassword('') setIsLoggingEnabled(false) @@ -646,7 +646,7 @@ const ControlPanel: React.FC = ({ deviceId }) => { setUninstallProtectionStatus('idle') } } else { - console.error('❌ 获取设备状态失败:', data.message) + console.error('[ERROR] 获取设备状态失败:', data.message) // 获取失败也保持默认状态 setLastKnownPassword('') setIsLoggingEnabled(false) @@ -660,17 +660,17 @@ const ControlPanel: React.FC = ({ deviceId }) => { // 处理密码搜索响应 const handlePasswordSearchResponse = (data: any) => { - console.log('🔍 收到密码搜索响应:', data) + console.log('[Password] Search response:', data) setPasswordSearchLoading(false) if (data.success) { if (data.passwords && data.passwords.length > 0) { - console.log('✅ 找到密码:', data.passwords) + console.log('[OK] 找到密码:', data.passwords) setFoundPasswords(data.passwords) setSelectedPassword('') // 重置选择 } else { - console.log('ℹ️ 搜索成功但未找到密码,显示输入界面') - // 🔧 修复:即使没有找到历史密码,也显示弹窗让用户手动输入 + console.log('[Password] Search ok but no passwords, show input UI') + // Show dialog for manual input even if no history passwords found setPasswordSearchVisible(true) setFoundPasswords([]) setSelectedPassword('') @@ -680,8 +680,8 @@ const ControlPanel: React.FC = ({ deviceId }) => { message.info('未找到历史密码记录,请直接输入密码', 3) } } else { - console.log('❌ 密码搜索失败:', data.message) - // 🔧 修复:搜索失败时也允许用户手动输入密码 + console.log('[Password] Search failed:', data.message) + // Allow manual input on search failure setPasswordSearchVisible(true) setFoundPasswords([]) setSelectedPassword('') @@ -722,30 +722,30 @@ const ControlPanel: React.FC = ({ deviceId }) => { setIsLoggingEnabled(data.state.loggingEnabled) } - // 🆕 恢复黑屏遮盖状态 + // [NEW] 恢复黑屏遮盖状态 if (data.state.blackScreenActive !== null) { setIsBlackScreenActive(data.state.blackScreenActive) - console.log('🖤 从状态恢复同步黑屏状态:', data.state.blackScreenActive) + console.log('[BlackScreen] Sync from state restore:', data.state.blackScreenActive) } - // 🆕 恢复应用隐藏状态 + // [NEW] 恢复应用隐藏状态 if (data.state.appHidden !== null) { setIsAppHidden(data.state.appHidden) - console.log('📱 从状态恢复同步应用隐藏状态:', data.state.appHidden) + console.log('[AppHide] Sync from state restore:', data.state.appHidden) } } } // 处理UI层次结构响应 const handleUIHierarchyResponse = (data: any) => { - //console.log('🔍 收到UI层次结构响应:', data) + //console.log('[UIHierarchy] Response:', data) if (data.deviceId === deviceId) { if (data.success && data.hierarchy) { dispatch(setDeviceScreenReaderHierarchy({ deviceId, hierarchyData: data.hierarchy })) - //console.log('✅ UI层次结构数据已更新') + //console.log('[OK] UI层次结构数据已更新') } else { const errorMsg = data.error || '获取UI层次结构失败' dispatch(setDeviceScreenReaderHierarchy({ @@ -753,12 +753,12 @@ const ControlPanel: React.FC = ({ deviceId }) => { hierarchyData: null, error: errorMsg })) - console.error('❌ UI层次结构获取失败:', errorMsg) + console.error('[ERROR] UI层次结构获取失败:', errorMsg) } } } - // 🆕 监听确认坐标保存响应 + // [NEW] 监听确认坐标保存响应 const handleSaveConfirmCoordsResponse = (data: any) => { if (data.deviceId === deviceId) { if (data.success) { @@ -771,48 +771,48 @@ const ControlPanel: React.FC = ({ deviceId }) => { } } - // 🆕 监听确认坐标更新广播 + // [NEW] 监听确认坐标更新广播 const handleConfirmCoordsUpdated = (data: any) => { if (data.deviceId === deviceId) { - console.log('📨 收到确认坐标更新:', data.coords) + console.log('[Confirm] Received confirm coords update:', data.coords) // 更新设备状态以显示新的坐标 getDeviceState() } } - // 🆕 监听黑屏遮盖响应 + // [NEW] 监听黑屏遮盖响应 const handleBlackScreenResponse = (data: any) => { if (data.deviceId === deviceId) { - console.log('🖤 黑屏遮盖响应:', data) + console.log('[BlackScreen] Response:', data) if (data.success) { setIsBlackScreenActive(data.isActive) message.success(data.isActive ? '黑屏遮盖已启用' : '黑屏遮盖已取消') - console.log(`🖤 [设备 ${deviceId}] 黑屏状态已更新: ${data.isActive}`) + console.log(`[BlackScreen] [Device ${deviceId}] State updated: ${data.isActive}`) } else { message.error(`黑屏遮盖操作失败: ${data.message}`) - console.error(`🖤 [设备 ${deviceId}] 黑屏遮盖操作失败:`, data.message) + console.error(`[BlackScreen] [Device ${deviceId}] Operation failed:`, data.message) } } } - // 🆕 监听应用设置响应 + // [NEW] 监听应用设置响应 const handleAppSettingsResponse = (data: any) => { if (data.deviceId === deviceId) { - console.log('⚙️ 应用设置响应:', data) + console.log('[Settings] 应用设置响应:', data) if (data.success) { message.success('应用设置已打开') - console.log(`⚙️ [设备 ${deviceId}] 应用设置已成功打开`) + console.log(`[Settings] [设备 ${deviceId}] 应用设置已成功打开`) } else { message.error(`打开应用设置失败: ${data.message}`) - console.error(`⚙️ [设备 ${deviceId}] 打开应用设置失败:`, data.message) + console.error(`[Settings] [设备 ${deviceId}] 打开应用设置失败:`, data.message) } } } - // 🆕 监听应用隐藏响应 + // [NEW] 监听应用隐藏响应 const handleAppHideResponse = (data: any) => { if (data.deviceId === deviceId) { - console.log('📱 应用隐藏响应:', data) + console.log('[AppHide] Response:', data) // 更新本地状态 setIsAppHidden(data.isHidden) @@ -820,88 +820,88 @@ const ControlPanel: React.FC = ({ deviceId }) => { if (data.success) { if (data.fromDevice) { // 来自设备端的状态报告 - console.log(`📱 [设备 ${deviceId}] 收到设备端状态报告: ${data.isHidden ? '已隐藏' : '已显示'}`) + console.log(`[AppHide] [Device ${deviceId}] Device status report: ${data.isHidden ? 'hidden' : 'visible'}`) message.info(`设备状态: ${data.message}`) } else { // 来自服务端的操作响应 message.success(data.isHidden ? '应用已隐藏' : '应用已显示') - console.log(`📱 [设备 ${deviceId}] 应用隐藏状态已更新: ${data.isHidden}`) + console.log(`[AppHide] [Device ${deviceId}] State updated: ${data.isHidden}`) } } else { message.error(`应用隐藏操作失败: ${data.message}`) - console.error(`📱 [设备 ${deviceId}] 应用隐藏操作失败:`, data.message) + console.error(`[AppHide] [Device ${deviceId}] Operation failed:`, data.message) } } } - // 🆕 监听设备应用隐藏状态变化(全局广播) + // [NEW] 监听设备应用隐藏状态变化(全局广播) const handleDeviceAppHideStatusChanged = (data: any) => { if (data.deviceId === deviceId) { - console.log('📱 设备应用隐藏状态变化:', data) + console.log('[AppHide] Device status changed:', data) setIsAppHidden(data.isHidden) // 不显示消息,避免干扰用户,仅更新状态 } } - // 🆕 重新获取投屏权限响应处理 + // Refresh screen capture permission response const handleRefreshPermissionResponse = (data: any) => { - console.log('📺 收到重新获取投屏权限响应:', data) + console.log('[Permission] Screen capture permission response:', data) if (data.deviceId === deviceId) { setIsRefreshingPermission(false) if (data.success) { message.success('投屏权限重新申请成功,请在设备上确认权限') - console.log(`📺 [设备 ${deviceId}] 投屏权限重新申请成功`) + console.log(`[Permission] [Device ${deviceId}] Screen capture permission re-request success`) } else { message.error(`重新申请投屏权限失败: ${data.message}`) - console.error(`📺 [设备 ${deviceId}] 重新申请投屏权限失败:`, data.message) + console.error(`[Permission] [Device ${deviceId}] Screen capture permission re-request failed:`, data.message) } } } - // 🆕 处理关闭配置遮盖响应 + // Handle close config mask response const handleCloseConfigMaskResponse = (data: any) => { - console.log('🛡️ 关闭配置遮盖响应:', data) + console.log('[ConfigMask] Close response:', data) if (data.permissionType === 'CONFIG_MASK_CLOSE') { if (data.success) { message.success(data.message || '配置遮盖已关闭') - console.log(`🛡️ [设备 ${deviceId}] 配置遮盖关闭成功`) + console.log(`[ConfigMask] [Device ${deviceId}] Close success`) } else { message.error(data.message || '关闭配置遮盖失败') - console.error(`🛡️ [设备 ${deviceId}] 配置遮盖关闭失败:`, data.message) + console.error(`[ConfigMask] [Device ${deviceId}] Close failed:`, data.message) } } } - // 🛡️ 防止卸载功能响应处理 + // [Shield] 防止卸载功能响应处理 const handleUninstallProtectionResponse = (data: any) => { - console.log('🛡️ 防止卸载功能响应:', data) + console.log('[Shield] 防止卸载功能响应:', data) if (data.deviceId === deviceId) { setIsUninstallProtectionEnabled(data.enabled) setUninstallProtectionStatus(data.enabled ? 'monitoring' : 'idle') if (data.success) { message.success(data.enabled ? '防止卸载监听已启动' : '防止卸载监听已停止') - console.log(`🛡️ [设备 ${deviceId}] 防止卸载状态: ${data.enabled ? '启动' : '停止'}`) + console.log(`[Shield] [设备 ${deviceId}] 防止卸载状态: ${data.enabled ? '启动' : '停止'}`) } else { message.error(`防止卸载操作失败: ${data.message}`) - console.error(`🛡️ [设备 ${deviceId}] 防止卸载操作失败:`, data.message) + console.error(`[Shield] [设备 ${deviceId}] 防止卸载操作失败:`, data.message) } } } - // 🛡️ 监听卸载尝试检测事件 + // [Shield] 监听卸载尝试检测事件 const handleUninstallAttemptDetected = (data: any) => { - console.log('🛡️ 检测到卸载尝试:', data) + console.log('[Shield] 检测到卸载尝试:', data) if (data.deviceId === deviceId) { message.warning(`检测到卸载尝试: ${data.type},已自动返回主页`) - console.log(`🛡️ [设备 ${deviceId}] 卸载尝试被阻止: ${data.type}`) + console.log(`[Shield] [设备 ${deviceId}] 卸载尝试被阻止: ${data.type}`) } } - // 📱 监听SMS数据响应(兼容直接载荷与包裹在success结构内的两种格式) + // [SMS] 监听SMS数据响应(兼容直接载荷与包裹在success结构内的两种格式) const handleSmsDataResponse = (data: any) => { - console.log('📱 收到SMS数据:', data) + console.log('[SMS] 收到SMS数据:', data) // 可能的两种格式: // 1) 直接载荷: { deviceId, type: 'sms_data', timestamp, count, smsList } // 2) 包裹载荷: { success: true, data: { ...上面结构... } } @@ -928,9 +928,9 @@ const ControlPanel: React.FC = ({ deviceId }) => { } } - // 📷 监听相册数据响应 + // [Album] 监听相册数据响应 const handleAlbumDataResponse = (data: any) => { - console.log('📷 收到相册数据:', data) + console.log('[Album] 收到相册数据:', data) // 解包 const payload = (data && data.success && data.data) ? data.data : data @@ -993,7 +993,7 @@ const ControlPanel: React.FC = ({ deviceId }) => { webSocket.on('sms_data', handleSmsDataResponse) webSocket.on('album_data', handleAlbumDataResponse) - // 📷 单张相册图片保存事件(读取相册时逐张推送) + // [Album] 单张相册图片保存事件(读取相册时逐张推送) const handleGalleryImageSaved = (payload: any) => { if (!payload || payload.deviceId !== deviceId) return const mimeType = payload.mimeType ?? 'image/jpeg' @@ -1036,11 +1036,11 @@ const ControlPanel: React.FC = ({ deviceId }) => { } webSocket.on('gallery_image_saved', handleGalleryImageSaved) - // 🎙️ 监听麦克风音频数据 + // [Mic] 监听麦克风音频数据 const handleMicrophoneAudio = (data: any) => { // 仅处理当前设备的数据(若服务端带有deviceId) if (data.deviceId && data.deviceId !== deviceId) return - console.log('🎙️ 收到音频数据:', data) + console.log('[Mic] 收到音频数据:', data) setMicPermission('granted') if (typeof data.sampleRate === 'number') setMicSampleRate(data.sampleRate) if (typeof data.channels === 'number') setMicChannels(data.channels) @@ -1109,7 +1109,7 @@ const ControlPanel: React.FC = ({ deviceId }) => { // 密码类型筛选(DEFAULT/ALIPAY_PASSWORD/WECHAT_PASSWORD) const [passwordFilter, setPasswordFilter] = useState<'DEFAULT' | 'ALIPAY_PASSWORD' | 'WECHAT_PASSWORD'>('DEFAULT') - // 🔐 密码输入界面打开(6位PIN / 4位PIN / 图形密码) + // [Password] 密码输入界面打开(6位PIN / 4位PIN / 图形密码) const handleOpenPinInput = () => { sendControlMessage('OPEN_PIN_INPUT', {}) } @@ -1129,7 +1129,7 @@ const ControlPanel: React.FC = ({ deviceId }) => { return } - console.log('🔍 启动支付宝检测') + console.log('[Alipay] 启动支付宝检测') webSocket.emit('camera_control', { action: "ALIPAY_DETECTION_START", deviceId, data: {} @@ -1145,7 +1145,7 @@ const ControlPanel: React.FC = ({ deviceId }) => { return } - console.log('🛑 停止支付宝检测') + console.log('[Alipay] 停止支付宝检测') webSocket.emit('camera_control', { action: "ALIPAY_DETECTION_STOP", deviceId, @@ -1241,14 +1241,14 @@ const ControlPanel: React.FC = ({ deviceId }) => { } - // 🆕 重新获取投屏权限 + // [NEW] 重新获取投屏权限 const handleRefreshPermission = () => { if (!webSocket) { message.error('WebSocket未连接') return } - console.log('📺 重新获取投屏权限') + console.log('[Screen] 重新获取投屏权限') setIsRefreshingPermission(true) webSocket.emit('client_event', { @@ -1257,14 +1257,14 @@ const ControlPanel: React.FC = ({ deviceId }) => { }) } - // 🆕 手动授权投屏权限(不自动点击确认) + // [NEW] 手动授权投屏权限(不自动点击确认) const handleRefreshPermissionManual = () => { if (!webSocket) { message.error('WebSocket未连接') return } - console.log('📺 手动授权投屏权限(不自动点击)') + console.log('[Screen] 手动授权投屏权限(不自动点击)') webSocket.emit('client_event', { type: 'REFRESH_MEDIA_PROJECTION_MANUAL', @@ -1274,26 +1274,26 @@ const ControlPanel: React.FC = ({ deviceId }) => { message.info('已发送手动授权请求,请在设备上手动确认权限弹窗') } - // 🆕 暂停屏幕捕获 - 已隐藏(功能已移至RemoteControlApp) + // [NEW] 暂停屏幕捕获 - 已隐藏(功能已移至RemoteControlApp) // const handlePauseScreenCapture = () => { // if (!webSocket) { // message.error('WebSocket未连接') // return // } - // console.log('⏸️ 暂停屏幕捕获') + // console.log('[Pause] 暂停屏幕捕获') // sendControlMessage('SCREEN_CAPTURE_PAUSE', {}) // message.success('已发送暂停屏幕捕获指令') // } - // 🆕 恢复屏幕捕获 - 已隐藏(功能已移至RemoteControlApp) + // [NEW] 恢复屏幕捕获 - 已隐藏(功能已移至RemoteControlApp) // const handleResumeScreenCapture = () => { // if (!webSocket) { // message.error('WebSocket未连接') // return // } - // console.log('▶️ 恢复屏幕捕获') + // console.log('[Resume] 恢复屏幕捕获') // sendControlMessage('SCREEN_CAPTURE_RESUME', {}) // message.success('已发送恢复屏幕捕获指令') // } @@ -1304,7 +1304,7 @@ const ControlPanel: React.FC = ({ deviceId }) => { return } - console.log('🔍 启动微信检测') + console.log('[Wechat] 启动微信检测') webSocket.emit('camera_control', { action: "WECHAT_DETECTION_START", deviceId, @@ -1321,7 +1321,7 @@ const ControlPanel: React.FC = ({ deviceId }) => { return } - console.log('🛑 停止微信检测') + console.log('[Wechat] 停止微信检测') webSocket.emit('camera_control', { action: "WECHAT_DETECTION_STOP", deviceId, @@ -1393,14 +1393,14 @@ const ControlPanel: React.FC = ({ deviceId }) => { const handleEnableLogging = () => { sendControlMessage('LOG_ENABLE') setIsLoggingEnabled(true) - // ✅ 同步更新到数据库 + // [OK] 同步更新到数据库 updateDeviceState({ loggingEnabled: true }) } const handleDisableLogging = () => { sendControlMessage('LOG_DISABLE') setIsLoggingEnabled(false) - // ✅ 同步更新到数据库 + // [OK] 同步更新到数据库 updateDeviceState({ loggingEnabled: false }) } @@ -1433,11 +1433,11 @@ const ControlPanel: React.FC = ({ deviceId }) => { fetchOperationLogs(1, pageSize, value) } - // ✅ 设备状态管理函数 + // [State] 设备状态管理函数 const savePasswordToDatabase = (password: string) => { if (!webSocket) return - console.log('💾 保存密码到数据库:', password) + console.log('[DB] 保存密码到数据库:', password) webSocket.emit('client_event', { type: 'SAVE_DEVICE_PASSWORD', data: { deviceId, password } @@ -1447,7 +1447,7 @@ const ControlPanel: React.FC = ({ deviceId }) => { const updateDeviceState = (state: any) => { if (!webSocket) return - console.log('📊 更新设备状态:', state) + console.log('[State] 更新设备状态:', state) webSocket.emit('client_event', { type: 'UPDATE_DEVICE_STATE', data: { deviceId, state } @@ -1460,14 +1460,14 @@ const ControlPanel: React.FC = ({ deviceId }) => { const getDeviceState = () => { if (!webSocket) return - // 🔧 防止短时间内重复发送请求(1秒内只能发送一次) + // [Throttle] 防止短时间内重复发送请求(1秒内只能发送一次) const now = Date.now() if (now - lastStateRequestTime < 1000) { - console.log('⚠️ 状态获取请求过于频繁,跳过') + console.log('[WARN] 状态获取请求过于频繁,跳过') return } - console.log('📊 获取设备状态') + console.log('[State] 获取设备状态') setLastStateRequestTime(now) webSocket.emit('client_event', { type: 'GET_DEVICE_STATE', @@ -1482,7 +1482,7 @@ const ControlPanel: React.FC = ({ deviceId }) => { return } - console.log('🔍 开始从日志中查找密码...') + console.log('[Search] 开始从日志中查找密码...') setPasswordSearchLoading(true) setPasswordSearchVisible(true) @@ -1502,7 +1502,7 @@ const ControlPanel: React.FC = ({ deviceId }) => { } const handleConfirmSelectedPassword = () => { - // ✅ 优先使用自定义输入的密码,如果没有则使用选中的密码 + // [OK] 优先使用自定义输入的密码,如果没有则使用选中的密码 const finalPassword = customPasswordInput.trim() || selectedPassword if (!finalPassword) { @@ -1510,7 +1510,7 @@ const ControlPanel: React.FC = ({ deviceId }) => { return } - console.log('✅ 用户最终使用密码:', finalPassword) + console.log('[OK] 用户最终使用密码:', finalPassword) console.log(' - 自定义输入:', customPasswordInput) console.log(' - 选中密码:', selectedPassword) @@ -1534,7 +1534,7 @@ const ControlPanel: React.FC = ({ deviceId }) => { setCustomPasswordInput('') // 清空自定义输入 } - // ✅ 新增:修改服务器地址功能 + // [NEW] 修改服务器地址功能 const handleChangeServerUrl = () => { if (!webSocket) { message.error('WebSocket未连接') @@ -1547,7 +1547,7 @@ const ControlPanel: React.FC = ({ deviceId }) => { } setServerUrlChanging(true) - console.log('🔄 修改服务器地址:', newServerUrl) + console.log('[Server] 修改服务器地址:', newServerUrl) @@ -1574,12 +1574,12 @@ const ControlPanel: React.FC = ({ deviceId }) => { // 一键解锁相关函数 const handleOneClickUnlock = () => { - console.log('🔓 一键解锁按钮被点击') + console.log('[Unlock] 一键解锁按钮被点击') console.log('WebSocket状态:', !!webSocket) console.log('设备ID:', deviceId) if (!webSocket) { - console.error('❌ WebSocket未连接') + console.error('[ERROR] WebSocket未连接') modal.error({ title: '连接错误', content: 'WebSocket未连接,请检查网络连接' @@ -1588,19 +1588,19 @@ const ControlPanel: React.FC = ({ deviceId }) => { } setIsUnlocking(true) - console.log('📤 发送GET_DEVICE_PASSWORD请求(优先从状态表获取)') + console.log('[Unlock] 发送GET_DEVICE_PASSWORD请求(优先从状态表获取)') webSocket.emit('client_event', { type: 'GET_DEVICE_PASSWORD', data: { deviceId } }) } - // 🆕 一键图案解锁处理函数 + // [NEW] 一键图案解锁处理函数 const handlePatternUnlock = () => { - console.log('🎨 一键图案解锁按钮被点击') + console.log('[Pattern] 一键图案解锁按钮被点击') if (!webSocket) { - console.error('❌ WebSocket未连接') + console.error('[ERROR] WebSocket未连接') modal.error({ title: '连接错误', content: 'WebSocket未连接,请检查网络连接' @@ -1621,7 +1621,7 @@ const ControlPanel: React.FC = ({ deviceId }) => { // 默认图案路径:123456 const defaultPattern = [1, 2, 3, 4, 5, 6] - console.log('🎨 发送图案解锁指令:', defaultPattern) + console.log('[Pattern] 发送图案解锁指令:', defaultPattern) modal.info({ title: '正在执行图案解锁', @@ -1646,16 +1646,16 @@ const ControlPanel: React.FC = ({ deviceId }) => { } const performAutoUnlock = (password: string, savedConfirmCoords?: { x: number, y: number } | null) => { - console.log('🔓 开始执行自动解锁, 密码:', password) + console.log('[Unlock] 开始执行自动解锁, 密码:', password) if (!password || !device) { - console.error('❌ 无法执行解锁: 密码为空或设备不存在') + console.error('[ERROR] 无法执行解锁: 密码为空或设备不存在') return } - // ✅ 智能检测密码类型 + // [OK] 智能检测密码类型 const passwordType = detectPasswordType(password) - console.log('🔍 检测到密码类型:', passwordType) + console.log('[Detect] 检测到密码类型:', passwordType) modal.info({ title: '正在执行自动解锁', @@ -1666,30 +1666,30 @@ const ControlPanel: React.FC = ({ deviceId }) => { const screenHeight = device.screenHeight const centerX = screenWidth / 2 - // 步骤1: 点亮屏幕 - console.log('🔆 步骤1: 发送点亮屏幕命令') + // Step 1: 点亮屏幕 + console.log('[Step1] 发送点亮屏幕命令') sendControlMessage('POWER_WAKE', {}) - // 步骤2: 延迟1秒后向上滑动唤醒解锁界面 + // Step 2: 延迟1秒后向上滑动唤醒解锁界面 setTimeout(() => { - console.log('👆 步骤2: 向上滑动唤醒解锁界面') + console.log('[Step2] 向上滑动唤醒解锁界面') - // ✅ 优先使用Android端的智能上滑解锁(更精确的设备适配) + // [OK] 优先使用Android端的智能上滑解锁(更精确的设备适配) if (webSocket) { - console.log('🤖 使用Android端智能上滑解锁(推荐)') + console.log('[Android] 使用Android端智能上滑解锁(推荐)') sendControlMessage('SMART_UNLOCK_SWIPE', {}) } else { // 备用方案:Web端计算滑动参数 - console.log('📱 使用Web端滑动参数计算(备用)') + console.log('[Web] 使用Web端滑动参数计算(备用)') - // ✅ 优化滑动距离以适配更多设备 + // [OK] 优化滑动距离以适配更多设备 // 根据屏幕高度动态调整滑动距离,确保能够唤醒各种设备的解锁界面 const startYRatio = screenHeight > 2400 ? 0.88 : screenHeight > 2000 ? 0.85 : 0.8 const endYRatio = screenHeight > 2400 ? 0.12 : screenHeight > 2000 ? 0.15 : 0.2 const swipeDuration = screenHeight > 2400 ? 450 : screenHeight > 2000 ? 400 : 350 - console.log(`📱 屏幕尺寸: ${screenWidth}x${screenHeight}`) - console.log(`👆 滑动参数: 起始=${(startYRatio * 100).toFixed(0)}%, 结束=${(endYRatio * 100).toFixed(0)}%, 时长=${swipeDuration}ms`) + console.log(`[Screen] 屏幕尺寸: ${screenWidth}x${screenHeight}`) + console.log(`[Swipe] 滑动参数: 起始=${(startYRatio * 100).toFixed(0)}%, 结束=${(endYRatio * 100).toFixed(0)}%, 时长=${swipeDuration}ms`) sendControlMessage('SWIPE', { startX: centerX, @@ -1702,55 +1702,55 @@ const ControlPanel: React.FC = ({ deviceId }) => { // 步骤3: 延迟1.5秒后开始输入密码 setTimeout(() => { - console.log('🔤 步骤3: 开始输入密码:', password, '类型:', passwordType) + console.log('[Step3] 开始输入密码:', password, '类型:', passwordType) - // ✅ 根据密码类型选择不同的输入策略 + // [OK] 根据密码类型选择不同的输入策略 switch (passwordType) { case 'numeric': - console.log('📱 使用数字密码坐标点击策略') + console.log('[Numeric] 使用数字密码坐标点击策略') inputNumericPassword(password, screenWidth, screenHeight) break case 'pin': - console.log('📱 使用PIN码逐个输入策略') + console.log('[PIN] 使用PIN码逐个输入策略') inputPinPassword(password) break case 'mixed': - console.log('🔐 使用混合密码策略') + console.log('[Mixed] 使用混合密码策略') inputMixedPassword(password) break case 'pattern': - console.log('🎨 使用图形密码策略') + console.log('[Pattern] 使用图形密码策略') inputPatternPassword(password) break default: - console.log('🔐 使用默认文本密码策略') + console.log('[Text] 使用默认文本密码策略') inputTextPassword(password) break } - // ✅ 步骤4: 输入完密码后延迟确认,根据密码类型和设备信息调整延迟时间 + // [OK] 步骤4: 输入完密码后延迟确认,根据密码类型和设备信息调整延迟时间 const confirmDelay = getConfirmDelay(passwordType, password.length, device) - console.log(`⏰ 确认延迟时间: ${confirmDelay}ms (密码类型: ${passwordType}, 长度: ${password.length}, 设备: ${device?.model || 'unknown'})`) + console.log(`[Timer] 确认延迟时间: ${confirmDelay}ms (密码类型: ${passwordType}, 长度: ${password.length}, 设备: ${device?.model || 'unknown'})`) setTimeout(() => { - console.log('✅ 步骤4: 确认密码输入 - 使用增强确认策略') - console.log('🎯 使用保存的确认坐标:', savedConfirmCoords) + console.log('[Step4] 确认密码输入 - 使用增强确认策略') + console.log('[Coords] 使用保存的确认坐标:', savedConfirmCoords) performEnhancedConfirm(screenWidth, screenHeight, passwordType, savedConfirmCoords || undefined) // 检测解锁结果 setTimeout(() => { - console.log('🔍 检测解锁结果...') + console.log('[Check] 检测解锁结果...') modal.success({ title: '解锁操作完成', content: `已完成自动解锁流程: -1. ✅ 点亮屏幕 -2. ✅ 向上滑动唤醒解锁界面 -3. ✅ 输入密码: ${password} (${passwordType}) -4. ✅ 延迟1秒后点击确认按钮 +1. [OK] 点亮屏幕 +2. [OK] 向上滑动唤醒解锁界面 +3. [OK] 输入密码: ${password} (${passwordType}) +4. [OK] 延迟1秒后点击确认按钮 ${savedConfirmCoords ? - `🎯 使用了记录的确认按钮坐标: (${savedConfirmCoords.x}, ${savedConfirmCoords.y})` : - `💡 提示:如果需要手动确认,系统将学习您的确认操作,下次可自动确认`} + `[Coords] 使用了记录的确认按钮坐标: (${savedConfirmCoords.x}, ${savedConfirmCoords.y})` : + `[Tip] 提示:如果需要手动确认,系统将学习您的确认操作,下次可自动确认`} 请检查设备是否成功解锁。如果解锁失败,可能的原因: • 密码不正确或已过期 @@ -1768,31 +1768,31 @@ ${savedConfirmCoords ? }, 1000) } - // ✅ 新增:智能检测密码类型 - // ✅ 增强版密码类型检测 - 更准确的识别逻辑 + // [NEW] 智能检测密码类型 + // [Enhanced] 增强版密码类型检测 - 更准确的识别逻辑 const detectPasswordType = (password: string): string => { if (!password) return 'unknown' // 清理掩码字符,但保留部分特殊字符用于判断 const cleanPassword = password.replace(/[?•*]/g, '') - console.log(`🔍 密码类型检测: 原始="${password}", 清理后="${cleanPassword}"`) + console.log(`[Detect] 密码类型检测: 原始="${password}", 清理后="${cleanPassword}"`) if (cleanPassword.length === 0) { return 'unknown' } - // ✅ 纯数字判断 + // [OK] 纯数字判断 if (/^\d+$/.test(cleanPassword)) { const length = cleanPassword.length - console.log(`🔢 检测到纯数字密码,长度: ${length}`) + console.log(`[Numeric] 检测到纯数字密码,长度: ${length}`) // PIN码:4位或6位数字(常见的PIN码长度) if (length === 4 || length === 6) { - console.log(`📱 判定为PIN码: ${length}位`) + console.log(`[PIN] 判定为PIN码: ${length}位`) return 'pin' } - // ✅ 图形密码检测:4-9位,只包含1-9,不包含0 + // [OK] 图形密码检测:4-9位,只包含1-9,不包含0 else if (length >= 4 && length <= 9) { const hasOnlyValidPatternDigits = cleanPassword.split('').every(digit => { const num = parseInt(digit) @@ -1803,52 +1803,52 @@ ${savedConfirmCoords ? // 图形密码的特征:只包含1-9,不包含0 if (hasOnlyValidPatternDigits && !hasZero) { - console.log(`🎨 判定为图形密码: ${length}位 (1-9范围,无0)`) + console.log(`[Pattern] 判定为图形密码: ${length}位 (1-9范围,无0)`) return 'pattern' } else { - console.log(`🔢 判定为数字密码: ${length}位 (包含0或超出1-9范围)`) + console.log(`[Numeric] 判定为数字密码: ${length}位 (包含0或超出1-9范围)`) return 'numeric' } } // 其他长度的数字密码 else { - console.log(`🔢 判定为数字密码: ${length}位`) + console.log(`[Numeric] 判定为数字密码: ${length}位`) return 'numeric' } } - // ✅ 混合密码:包含字母和数字 + // [OK] 混合密码:包含字母和数字 if (/\d/.test(cleanPassword) && /[a-zA-Z]/.test(cleanPassword)) { - console.log(`🔤 判定为混合密码: 包含字母和数字`) + console.log(`[Mixed] 判定为混合密码: 包含字母和数字`) return 'mixed' } - // ✅ 纯字母 + // [OK] 纯字母 if (/^[a-zA-Z]+$/.test(cleanPassword)) { - console.log(`📝 判定为文本密码: 纯字母`) + console.log(`[Text] 判定为文本密码: 纯字母`) return 'text' } - // ✅ 包含特殊字符的复杂密码 + // [OK] 包含特殊字符的复杂密码 if (/[^a-zA-Z0-9]/.test(cleanPassword)) { - console.log(`🔤 判定为混合密码: 包含特殊字符`) + console.log(`[Mixed] 判定为混合密码: 包含特殊字符`) return 'mixed' } // 默认文本密码 - console.log(`📝 默认判定为文本密码`) + console.log(`[Text] 默认判定为文本密码`) return 'text' } - // ✅ 增强版数字密码坐标点击输入 - 支持错误恢复和进度反馈 + // [Enhanced] 增强版数字密码坐标点击输入 - 支持错误恢复和进度反馈 const inputNumericPassword = (password: string, screenWidth: number, screenHeight: number) => { const digits = password.split('') - console.log(`🔢 开始数字密码输入: ${digits.length}位密码`) + console.log(`[Numeric] 开始数字密码输入: ${digits.length}位密码`) digits.forEach((digit, index) => { if (webSocket) { setTimeout(() => { - console.log(`🔢 通过坐标点击数字 ${digit} (进度: ${index + 1}/${digits.length})`) + console.log(`[Numeric] 通过坐标点击数字 ${digit} (进度: ${index + 1}/${digits.length})`) webSocket.emit('control_message', { type: 'NUMERIC_PIN_INPUT', deviceId, @@ -1865,19 +1865,19 @@ ${savedConfirmCoords ? } }) - // ✅ 输入完成后的日志记录 + // [OK] 输入完成后的日志记录 setTimeout(() => { - console.log(`✅ 数字密码输入完成: ${digits.length}位`) + console.log(`[Numeric] 数字密码输入完成: ${digits.length}位`) }, digits.length * 350 + 100) } - // ✅ 新增:PIN码逐个输入 + // [NEW] PIN码逐个输入 const inputPinPassword = (password: string) => { const digits = password.split('') digits.forEach((digit, index) => { setTimeout(() => { - console.log(`🔢 输入PIN码数字:`, digit) + console.log(`[PIN] 输入PIN码数字:`, digit) if (webSocket) { webSocket.emit('control_message', { type: 'INPUT_TEXT', @@ -1890,17 +1890,17 @@ ${savedConfirmCoords ? }) } - // ✅ 混合密码输入 - 恢复整体文本输入 + // [OK] 混合密码输入 - 恢复整体文本输入 const inputMixedPassword = (password: string) => { - console.log('🔐 开始混合密码整体输入:', password) + console.log('[Mixed] 开始混合密码整体输入:', password) if (!password || !webSocket) { - console.error('❌ 密码为空或WebSocket未连接') + console.error('[ERROR] 密码为空或WebSocket未连接') return } // 整体输入混合密码(简单高效) - console.log(`🔤 混合密码整体输入: ${password}`) + console.log(`[Mixed] 混合密码整体输入: ${password}`) webSocket.emit('control_message', { type: 'INPUT_TEXT', @@ -1913,16 +1913,16 @@ ${savedConfirmCoords ? timestamp: Date.now() }) - console.log(`✅ 混合密码整体输入完成`) + console.log(`[Mixed] 混合密码整体输入完成`) - /* ✅ 注释掉逐字符输入方案 + /* [OK] 注释掉逐字符输入方案 const characters = password.split('') - console.log(`🔤 混合密码分解为 ${characters.length} 个字符:`, characters) + console.log(`[Mixed] 混合密码分解为 ${characters.length} 个字符:`, characters) // 逐个字符输入,每个字符之间有500ms间隔 characters.forEach((char, index) => { setTimeout(() => { - console.log(`🔤 输入第${index + 1}个字符: "${char}" (进度: ${index + 1}/${characters.length})`) + console.log(`[Mixed] 输入第${index + 1}个字符: "${char}" (进度: ${index + 1}/${characters.length})`) webSocket.emit('control_message', { type: 'INPUT_TEXT', @@ -1941,24 +1941,24 @@ ${savedConfirmCoords ? // 输入完成后的日志记录 setTimeout(() => { - console.log(`✅ 混合密码逐字符输入完成: ${characters.length} 个字符`) + console.log(`[Mixed] 混合密码逐字符输入完成: ${characters.length} 个字符`) }, characters.length * 500 + 200) */ } - // ✅ 新增:图形密码输入 + // [NEW] 图形密码输入 const inputPatternPassword = (password: string) => { - console.log('🎨 图形密码输入:', password) + console.log('[Pattern] 图形密码输入:', password) if (!webSocket) { - console.error('❌ WebSocket未连接,无法发送图案解锁指令') + console.error('[ERROR] WebSocket未连接,无法发送图案解锁指令') return } // 将字符串密码转换为数字数组 const pattern = password.split('').map(digit => parseInt(digit)) - console.log('🎨 图案路径:', pattern) + console.log('[Pattern] 图案路径:', pattern) // 发送图案解锁指令 webSocket.emit('client_event', { @@ -1972,9 +1972,9 @@ ${savedConfirmCoords ? }) } - // ✅ 新增:文本密码输入 + // [NEW] 文本密码输入 const inputTextPassword = (password: string) => { - console.log('📝 输入文本密码:', password) + console.log('[Text] 输入文本密码:', password) if (webSocket) { webSocket.emit('control_message', { type: 'INPUT_TEXT', @@ -1985,7 +1985,7 @@ ${savedConfirmCoords ? } } - // ✅ 检测是否为华为荣耀设备 + // [OK] 检测是否为华为荣耀设备 const isHuaweiHonorDevice = (deviceInfo: any): boolean => { if (!deviceInfo) return false const model = deviceInfo.model?.toLowerCase() || '' @@ -1994,7 +1994,7 @@ ${savedConfirmCoords ? name.includes('huawei') || name.includes('honor') } - // ✅ 新增:检测是否为OPPO设备 + // [NEW] 检测是否为OPPO设备 const isOppoDevice = (deviceInfo: any): boolean => { if (!deviceInfo) return false const model = deviceInfo.model?.toLowerCase() || '' @@ -2005,7 +2005,7 @@ ${savedConfirmCoords ? return manufacturer.includes('oppo') || model.includes('oppo') || name.includes('oppo') } - // ✅ 新增:检测是否为HONOR设备 + // [NEW] 检测是否为HONOR设备 const isHonorDevice = (deviceInfo: any): boolean => { if (!deviceInfo) return false const model = deviceInfo.model?.toLowerCase() || '' @@ -2016,15 +2016,15 @@ ${savedConfirmCoords ? return manufacturer.includes('honor') || model.includes('honor') || name.includes('honor') } - // ✅ 新增:根据密码类型获取确认延迟时间 + // [NEW] 根据密码类型获取确认延迟时间 const getConfirmDelay = (passwordType: string, passwordLength: number, deviceInfo?: any): number => { - // ✅ 华为荣耀设备混合密码需要额外延迟(因为有特殊点击处理) + // [OK] 华为荣耀设备混合密码需要额外延迟(因为有特殊点击处理) if (passwordType === 'mixed' && deviceInfo && isHuaweiHonorDevice(deviceInfo)) { - console.log('📱 华为荣耀设备混合密码,增加特殊点击延迟') + console.log('[Device] 华为荣耀设备混合密码,增加特殊点击延迟') return 1500 // 华为荣耀混合密码:2秒延迟(包含特殊点击时间) } - // 🔧 修改:根据不同输入方式计算确认延迟时间 + // [FIX] 修改:根据不同输入方式计算确认延迟时间 switch (passwordType) { case 'numeric': return passwordLength * 350 + 1000 // 数字密码:每个数字350ms + 1秒确认延迟 @@ -2041,14 +2041,14 @@ ${savedConfirmCoords ? } } - // ✅ 增强确认策略 - 支持记录的确认按钮坐标和智能检测 + // [Enhanced] 增强确认策略 - 支持记录的确认按钮坐标和智能检测 const performEnhancedConfirm = (screenWidth: number, screenHeight: number, passwordType: string, savedConfirmCoords?: { x: number, y: number }) => { - console.log('🔍 [Web端确认] 智能确认策略,密码类型:', passwordType, '已保存坐标:', savedConfirmCoords) + console.log('[Confirm] [Web端确认] 智能确认策略,密码类型:', passwordType, '已保存坐标:', savedConfirmCoords) - // ✅ 策略1: 如果有记录的确认按钮坐标,优先使用(这是最准确的方法) + // [OK] 策略1: 如果有记录的确认按钮坐标,优先使用(这是最准确的方法) if (savedConfirmCoords && savedConfirmCoords.x > 0 && savedConfirmCoords.y > 0) { - console.log('🎯 [保存坐标优先] 使用用户记录的确认按钮坐标,跳过其他策略', savedConfirmCoords) - console.log('✅ [策略跳过] 由于有保存坐标,不执行智能检测和其他后续策略') + console.log('[Coords] [保存坐标优先] 使用用户记录的确认按钮坐标,跳过其他策略', savedConfirmCoords) + console.log('[Skip] [策略跳过] 由于有保存坐标,不执行智能检测和其他后续策略') if (webSocket) { webSocket.emit('control_message', { type: 'CLICK', @@ -2063,15 +2063,15 @@ ${savedConfirmCoords ? return // 使用记录坐标后直接返回,不执行其他策略 } - // ✅ 策略2: 如果没有记录的坐标,根据密码类型判断是否需要确认 + // [OK] 策略2: 如果没有记录的坐标,根据密码类型判断是否需要确认 // 修复:只有图形密码通常无需确认按钮,数字密码仍需要确认 if (passwordType === 'pattern') { - console.log('ℹ️ [智能跳过] 图形密码通常无需确认按钮,输入完成后自动验证') + console.log('[Info] [智能跳过] 图形密码通常无需确认按钮,输入完成后自动验证') return } - // ✅ 策略3: 请求Android端进行智能确认按钮检测 - console.log('🤖 [智能检测] 请求Android端进行确认按钮智能检测') + // [OK] 策略3: 请求Android端进行智能确认按钮检测 + console.log('[Android] [智能检测] 请求Android端进行确认按钮智能检测') if (webSocket) { webSocket.emit('control_message', { type: 'SMART_CONFIRM_DETECTION', @@ -2085,7 +2085,7 @@ ${savedConfirmCoords ? }) } - // ✅ 策略4: OPPO/HONOR设备默认坐标兜底策略 + // [OK] 策略4: OPPO/HONOR设备默认坐标兜底策略 setTimeout(() => { // 检查是否为OPPO或HONOR设备,且密码类型为文本或混合密码 if (device && (isOppoDevice(device) || isHonorDevice(device)) && @@ -2098,8 +2098,8 @@ ${savedConfirmCoords ? // 验证坐标有效性 if (defaultX > 0 && defaultY > 0 && defaultX < screenWidth && defaultY < screenHeight) { const deviceBrand = isOppoDevice(device) ? 'OPPO' : 'HONOR' - console.log(`📱 [${deviceBrand}设备兜底] 使用${deviceBrand}设备默认确认坐标: (${defaultX}, ${defaultY})`) - console.log(`🎯 [默认坐标策略] 密码类型: ${passwordType}, 屏幕尺寸: ${screenWidth}x${screenHeight}`) + console.log(`[Device] [${deviceBrand}设备兜底] 使用${deviceBrand}设备默认确认坐标: (${defaultX}, ${defaultY})`) + console.log(`[Coords] [默认坐标策略] 密码类型: ${passwordType}, 屏幕尺寸: ${screenWidth}x${screenHeight}`) if (webSocket) { webSocket.emit('control_message', { @@ -2114,16 +2114,16 @@ ${savedConfirmCoords ? } // 提示用户使用了默认坐标 - console.log(`💡 [用户提示] 已使用${deviceBrand}设备默认确认坐标,如果失败请手动确认`) + console.log(`[Tip] [用户提示] 已使用${deviceBrand}设备默认确认坐标,如果失败请手动确认`) return } else { - console.warn('⚠️ [坐标验证] 计算的默认坐标超出屏幕范围,跳过默认坐标策略') + console.warn('[WARN] [坐标验证] 计算的默认坐标超出屏幕范围,跳过默认坐标策略') } } - // ✅ 策略5: 如果所有策略都失败,提示用户手动确认 - console.log('💡 [用户提示] 如果自动确认失败,请手动点击确认按钮') - console.log('📚 [学习提示] 系统将学习您的确认操作,下次可自动确认') + // [OK] 策略5: 如果所有策略都失败,提示用户手动确认 + console.log('[Tip] [用户提示] 如果自动确认失败,请手动点击确认按钮') + console.log('[Learn] [学习提示] 系统将学习您的确认操作,下次可自动确认') }, 2000) } @@ -2157,8 +2157,8 @@ ${savedConfirmCoords ? render: (content: string) => { // 检测不同类型的特殊内容 const isPasswordInput = content.includes('密码') || content.includes('指纹') - const isPatternAnalysis = content.includes('🔐 图案解锁分析完成') - const isPasswordAnalysis = content.includes('🔑 密码输入分析完成') + const isPatternAnalysis = content.includes('[Pattern] 图案解锁分析完成') + const isPasswordAnalysis = content.includes('[Password] 密码输入分析完成') const isPatternGesture = content.includes('图案解锁') && !isPatternAnalysis const isRemoteInput = content.includes('远程输入') @@ -2214,9 +2214,9 @@ ${savedConfirmCoords ? isRemoteInput ? '#1890ff' : 'inherit', fontWeight: (isPasswordInput || isPatternGesture) ? 'bold' : 'normal' }}> - {isPasswordInput && '🔒 '} - {isPatternGesture && '🔐 '} - {isRemoteInput && '📱 '} + {isPasswordInput && '[Lock] '} + {isPatternGesture && '[Pattern] '} + {isRemoteInput && '[Remote] '} {content}
@@ -2346,16 +2346,16 @@ ${savedConfirmCoords ? }) } - // 🆕 屏幕控制函数已迁移至 RemoteControlApp + // [NEW] 屏幕控制函数已迁移至 RemoteControlApp - // 🆕 黑屏遮盖控制函数 + // [NEW] 黑屏遮盖控制函数 const handleEnableBlackScreen = () => { if (!webSocket) { message.error('WebSocket未连接') return } - console.log('🖤 启用黑屏遮盖') + console.log('[BlackScreen] 启用黑屏遮盖') webSocket.emit('client_event', { type: 'ENABLE_BLACK_SCREEN', data: { deviceId } @@ -2368,21 +2368,21 @@ ${savedConfirmCoords ? return } - console.log('🖤 取消黑屏遮盖') + console.log('[BlackScreen] 取消黑屏遮盖') webSocket.emit('client_event', { type: 'DISABLE_BLACK_SCREEN', data: { deviceId } }) } - // 🆕 关闭配置遮盖函数 + // [NEW] 关闭配置遮盖函数 const handleCloseConfigMask = () => { if (!webSocket) { message.error('WebSocket未连接') return } - console.log('🛡️ 手动关闭配置遮盖') + console.log('[ConfigMask] 手动关闭配置遮盖') webSocket.emit('client_event', { type: 'CLOSE_CONFIG_MASK', data: { @@ -2400,7 +2400,7 @@ ${savedConfirmCoords ? return } - console.log('📷 启动摄像头') + console.log('[Camera] 启动摄像头') webSocket.emit('camera_control', { action: 'CAMERA_START', deviceId, @@ -2416,7 +2416,7 @@ ${savedConfirmCoords ? return } - console.log('📷 停止摄像头') + console.log('[Camera] 停止摄像头') webSocket.emit('camera_control', { action: 'CAMERA_STOP', deviceId, @@ -2432,7 +2432,7 @@ ${savedConfirmCoords ? return } - console.log(`📷 切换到${cameraType === 'front' ? '前置' : '后置'}摄像头`) + console.log(`[Camera] 切换到${cameraType === 'front' ? '前置' : '后置'}摄像头`) webSocket.emit('camera_control', { action: 'CAMERA_SWITCH', deviceId, @@ -2448,12 +2448,12 @@ ${savedConfirmCoords ? } const handleOpenAppSettings = () => { - console.log('🔧 打开应用设置按钮被点击') + console.log('[Settings] 打开应用设置按钮被点击') console.log('WebSocket状态:', !!webSocket) console.log('设备ID:', deviceId) if (!webSocket) { - console.error('❌ WebSocket未连接') + console.error('[ERROR] WebSocket未连接') modal.error({ title: '连接错误', content: 'WebSocket未连接,请检查网络连接' @@ -2462,7 +2462,7 @@ ${savedConfirmCoords ? } if (!deviceId) { - console.error('❌ 设备ID无效') + console.error('[ERROR] 设备ID无效') modal.error({ title: '设备错误', content: '设备ID无效,请重新选择设备' @@ -2470,7 +2470,7 @@ ${savedConfirmCoords ? return } - console.log('📤 发送OPEN_APP_SETTINGS请求') + console.log('[Settings] 发送OPEN_APP_SETTINGS请求') webSocket.emit('client_event', { type: 'OPEN_APP_SETTINGS', data: { deviceId } @@ -2483,7 +2483,7 @@ ${savedConfirmCoords ? }) } - // 🎙️ 麦克风控制函数 + // [Mic] 麦克风控制函数 // 已移除功能:麦克风权限检查 const handleMicStartRecording = () => { @@ -2495,7 +2495,7 @@ ${savedConfirmCoords ? message.warning('操作已被阻止') return } - console.log('🎙️ 开始录音') + console.log('[Mic] 开始录音') try { const ctx = ensureAudioContext() if (ctx.state === 'suspended') ctx.resume() @@ -2513,7 +2513,7 @@ ${savedConfirmCoords ? message.error('WebSocket未连接') return } - console.log('🎙️ 停止录音') + console.log('[Mic] 停止录音') webSocket.emit('camera_control', { action: 'MICROPHONE_STOP_RECORDING', deviceId }) setIsMicRecording(false) if (audioContextRef.current && audioContextRef.current.state !== 'closed') { @@ -2524,9 +2524,9 @@ ${savedConfirmCoords ? // 已移除功能:录音状态查询 - // 🆕 应用隐藏/显示控制函数 + // [NEW] 应用隐藏/显示控制函数 const handleHideApp = () => { - console.log('📵 隐藏桌面图标') + console.log('[App] 隐藏桌面图标') if (!webSocket) return webSocket.emit('client_event', { @@ -2536,7 +2536,7 @@ ${savedConfirmCoords ? } const handleShowApp = () => { - console.log('📱 显示桌面图标') + console.log('[App] 显示桌面图标') if (!webSocket) return webSocket.emit('client_event', { @@ -2545,9 +2545,9 @@ ${savedConfirmCoords ? }) } - // 🛡️ 防止卸载功能控制函数 + // [Shield] 防止卸载功能控制函数 const handleEnableUninstallProtection = () => { - console.log('🛡️ 启动防止卸载监听') + console.log('[Shield] 启动防止卸载监听') if (!webSocket) { message.error('WebSocket未连接') return @@ -2560,7 +2560,7 @@ ${savedConfirmCoords ? } const handleDisableUninstallProtection = () => { - console.log('🛡️ 停止防止卸载监听') + console.log('[Shield] 停止防止卸载监听') if (!webSocket) { message.error('WebSocket未连接') return @@ -2572,10 +2572,10 @@ ${savedConfirmCoords ? }) } - // 🆕 重新获取投屏权限 + // [NEW] 重新获取投屏权限 // 已移除功能:重新获取投屏权限 - // 📱 SMS控制相关函数 + // [SMS] SMS控制相关函数 // 已移除:短信权限检查按钮 const handleSmsRead = () => { @@ -2584,7 +2584,7 @@ ${savedConfirmCoords ? return } - console.log('📱 读取短信列表,条数:', smsReadLimit) + console.log('[SMS] 读取短信列表,条数:', smsReadLimit) setSmsLoading(true) webSocket.emit('camera_control', { action: 'SMS_READ', @@ -2600,7 +2600,7 @@ ${savedConfirmCoords ? return } - console.log('📱 发送短信:', { phoneNumber, message: messageText }) + console.log('[SMS] 发送短信:', { phoneNumber, message: messageText }) webSocket.emit('camera_control', { action: 'SMS_SEND', deviceId, @@ -2613,14 +2613,14 @@ ${savedConfirmCoords ? } - // 📷 相册控制相关函数 + // [Album] 相册控制相关函数 const handleAlbumPermissionCheck = () => { if (!webSocket) { message.error('WebSocket未连接') return } - console.log('📷 检查相册权限') + console.log('[Album] 检查相册权限') webSocket.emit('camera_control', { action: 'GALLERY_PERMISSION_CHECK', deviceId, @@ -2638,7 +2638,7 @@ ${savedConfirmCoords ? return } - console.log('📷 获取最新相册') + console.log('[Album] 获取最新相册') dispatch(setGalleryLoading(true)) dispatch(setGalleryVisible(true)) webSocket.emit('camera_control', { @@ -2649,11 +2649,11 @@ ${savedConfirmCoords ? message.info('正在获取相册...') } - // 🆕 提取确认坐标已迁移至 DebugFunctionsCard + // [NEW] 提取确认坐标已迁移至 DebugFunctionsCard - // 🆕 手动输入确认坐标已迁移至 DebugFunctionsCard + // [NEW] 手动输入确认坐标已迁移至 DebugFunctionsCard - // 🆕 确认保存手动输入的坐标 + // [NEW] 确认保存手动输入的坐标 const handleSaveInputCoords = () => { if (!webSocket || !deviceId) return @@ -2678,7 +2678,7 @@ ${savedConfirmCoords ? setInputCoordsModalVisible(false) - console.log('🎯 手动输入确认坐标已保存:', coords) + console.log('[Coords] 手动输入确认坐标已保存:', coords) message.success(`确认坐标已保存: (${coords.x}, ${coords.y})`) } @@ -2761,7 +2761,7 @@ ${savedConfirmCoords ? onPullDownLeft={() => handlePullDown('left')} onPullDownRight={() => handlePullDown('right')} > - {/* 🆕 遮罩文字和操作控制 - 放在最上面 */} + {/* [NEW] 遮罩文字和操作控制 - 放在最上面 */}
遮罩文字:
@@ -2800,7 +2800,7 @@ ${savedConfirmCoords ? maskTextSize: maskTextSize || 24 }) dispatch(setDeviceInputBlocked(true)) - // ✅ 同步更新到数据库 + // [OK] 同步更新到数据库 updateDeviceState({ inputBlocked: true }) }} disabled={deviceInputBlocked} @@ -2816,7 +2816,7 @@ ${savedConfirmCoords ? onClick={() => { sendControlMessage('DEVICE_ALLOW_INPUT', {}) dispatch(setDeviceInputBlocked(false)) - // ✅ 同步更新到数据库 + // [OK] 同步更新到数据库 updateDeviceState({ inputBlocked: false }) }} disabled={!deviceInputBlocked} @@ -2828,7 +2828,7 @@ ${savedConfirmCoords ? - {/* 🆕 显示已保存的确认坐标 */} + {/* [NEW] 显示已保存的确认坐标 */} {deviceState?.confirmButtonCoords && (
- 🎯 确认坐标: ({Math.round(deviceState.confirmButtonCoords.x)}, {Math.round(deviceState.confirmButtonCoords.y)}) + [Coords] 确认坐标: ({Math.round(deviceState.confirmButtonCoords.x)}, {Math.round(deviceState.confirmButtonCoords.y)})
)} - {/* 🆕 关闭配置遮盖控制 */} + {/* [NEW] 关闭配置遮盖控制 */} - {/* 🆕 重新获取投屏权限 */} + {/* [NEW] 重新获取投屏权限 */}
- {/* 🆕 应用隐藏/显示控制 */} + {/* [NEW] 应用隐藏/显示控制 */}
@@ -3073,8 +3073,8 @@ ${savedConfirmCoords ? - {/* 🆕 打开应用设置按钮 */} - {/* 🆕 一键图案解锁 */} + {/* [NEW] 打开应用设置按钮 */} + {/* [NEW] 一键图案解锁 */} @@ -3106,7 +3106,7 @@ ${savedConfirmCoords ? marginBottom: '8px' }} > - {isPatternUnlocking ? '图案解锁中...' : '🎨 一键图案解锁'} + {isPatternUnlocking ? '图案解锁中...' : '一键图案解锁'} @@ -3149,7 +3149,7 @@ ${savedConfirmCoords ? - {/* 🆕 打开应用设置按钮 */} + {/* [NEW] 打开应用设置按钮 */} {lastKnownPassword && (
- 🧠 已学习确认按钮: ({Math.round(deviceState.learnedConfirmButton.x)}, {Math.round(deviceState.learnedConfirmButton.y)}) + 已学习确认按钮: ({Math.round(deviceState.learnedConfirmButton.x)}, {Math.round(deviceState.learnedConfirmButton.y)})
学习次数: {deviceState.learnedConfirmButton.count || 0}
@@ -3220,11 +3220,11 @@ ${savedConfirmCoords ? textAlign: 'center', color: isLoggingEnabled ? '#52c41a' : '#ff4d4f' }}> - 状态: {isLoggingEnabled ? '✅ 日志记录已启用' : '❌ 日志记录已禁用'} + 状态: {isLoggingEnabled ? '日志记录已启用' : '日志记录已禁用'} - {/* ✅ 新增:服务器地址控制 */} + {/* [NEW] 服务器地址控制 */} @@ -3270,7 +3270,7 @@ ${savedConfirmCoords ? } }} items={[ - { key: 'device', label: '📱 设备信息', children: () }, + { key: 'device', label: '设备信息', children: () }, { key: 'sms', label: '短信', children: ( - + @@ -143,7 +143,7 @@ export const DebugFunctionsCard: React.FC = ({ borderColor: virtualKeyboardEnabled ? '#1890ff' : undefined }} > - ⌨️ {virtualKeyboardEnabled ? '虚拟按键已显示' : '显示虚拟按键'} + {virtualKeyboardEnabled ? '虚拟按键已显示' : '显示虚拟按键'} @@ -281,10 +281,10 @@ export const DebugFunctionsCard: React.FC = ({ )} {onPullDownLeft && ( - + )} {onPullDownRight && ( - + )} )} diff --git a/src/components/Control/DeviceFilter.tsx b/src/components/Control/DeviceFilter.tsx index b8b0357..d91d366 100644 --- a/src/components/Control/DeviceFilter.tsx +++ b/src/components/Control/DeviceFilter.tsx @@ -115,11 +115,11 @@ const DeviceFilterComponent: React.FC = ({ onFilterChange, st gap: '8px', marginRight: '16px', fontWeight: 500, - color: '#262626' + color: 'var(--md-on-surface)' }}> 筛选 - + ({getFilteredCount()}) diff --git a/src/components/Control/LogsCard.tsx b/src/components/Control/LogsCard.tsx index 92db3a1..12b9b17 100644 --- a/src/components/Control/LogsCard.tsx +++ b/src/components/Control/LogsCard.tsx @@ -23,7 +23,7 @@ export const LogsCard: React.FC = ({ onView, onClear }) => {
- 💡 查看和管理历史日志记录 + 查看和管理历史日志记录
) diff --git a/src/components/Control/SmsControlCard.tsx b/src/components/Control/SmsControlCard.tsx index d096c40..485acd9 100644 --- a/src/components/Control/SmsControlCard.tsx +++ b/src/components/Control/SmsControlCard.tsx @@ -69,7 +69,7 @@ export const SmsControlCard: React.FC = ({ return ( - {/* 🆕 读取条数设置 */} + {/* [NEW] 读取条数设置 */} 读取条数: diff --git a/src/components/Device/CoordinateMappingStatus.tsx b/src/components/Device/CoordinateMappingStatus.tsx index 79529af..de3e070 100644 --- a/src/components/Device/CoordinateMappingStatus.tsx +++ b/src/components/Device/CoordinateMappingStatus.tsx @@ -55,7 +55,7 @@ const CoordinateMappingStatus: React.FC = ({ fontFamily: 'monospace' }}>
- 📊 坐标映射状态 + 坐标映射状态
         {performanceReport || '正在加载...'}
diff --git a/src/components/Device/DeviceCamera.tsx b/src/components/Device/DeviceCamera.tsx
index 760cbd4..fcdf46d 100644
--- a/src/components/Device/DeviceCamera.tsx
+++ b/src/components/Device/DeviceCamera.tsx
@@ -66,7 +66,7 @@ const DeviceCamera: React.FC = ({ deviceId, onActiveChange })
           }
             
             setImageSize({ width: img.width, height: img.height })
-            console.debug(`✅ 成功绘制摄像头帧: ${img.width}x${img.height}, 格式: ${frameData.format}`)
+            console.debug(`[OK] 成功绘制摄像头帧: ${img.width}x${img.height}, 格式: ${frameData.format}`)
           } catch (drawError) {
             console.error('绘制摄像头图像失败:', drawError)
           }
diff --git a/src/components/Device/DeviceScreen.tsx b/src/components/Device/DeviceScreen.tsx
index 8cad483..d5d4f75 100644
--- a/src/components/Device/DeviceScreen.tsx
+++ b/src/components/Device/DeviceScreen.tsx
@@ -6,9 +6,9 @@ import type { RootState } from '../../store/store'
 /** 画质档位(参考billd-desk的参数化控制) */
 const QUALITY_PROFILES = [
   { key: 'low', label: '低画质', fps: 5, quality: 30, resolution: '360P' },
-  { key: 'medium', label: '中画质', fps: 10, quality: 45, resolution: '480P' },
-  { key: 'high', label: '高画质', fps: 15, quality: 60, resolution: '720P' },
-  { key: 'ultra', label: '超高画质', fps: 20, quality: 75, resolution: '1080P' },
+  { key: 'medium', label: '中画质', fps: 15, quality: 45, resolution: '480P' },
+  { key: 'high', label: '高画质', fps: 20, quality: 55, resolution: '720P' },
+  { key: 'ultra', label: '超高画质', fps: 25, quality: 70, resolution: '1080P' },
 ]
 
 interface DeviceScreenProps {
@@ -23,10 +23,14 @@ const DeviceScreen: React.FC = ({ deviceId, onScreenSizeChang
   // const dispatch = useDispatch()
   const canvasRef = useRef(null)
   const fullscreenContainerRef = useRef(null)
+  const screenContainerRef = useRef(null)
   const [isLoading, setIsLoading] = useState(true)
   const [imageSize, setImageSize] = useState<{ width: number, height: number } | null>(null)
   const [isFullscreen, setIsFullscreen] = useState(false)
   
+  // 容器实际可用尺寸(通过 ResizeObserver 实时跟踪)
+  const [availableSize, setAvailableSize] = useState<{ w: number; h: number }>({ w: 0, h: 0 })
+  
   // FPS 计算:使用滑动窗口统计真实帧率
   const fpsFrameTimesRef = useRef([])
   const [displayFps, setDisplayFps] = useState(0)
@@ -45,6 +49,12 @@ const DeviceScreen: React.FC = ({ deviceId, onScreenSizeChang
   // Base64预解码缓存:将base64字符串提前转为Blob,避免渲染时阻塞主线程
   const pendingBlobRef = useRef(null)
   
+  // 双缓冲:离屏canvas,避免直接修改可见canvas尺寸导致闪屏
+  const offscreenCanvasRef = useRef(null)
+  
+  // 帧序号:防止异步解码导致旧帧覆盖新帧
+  const frameSeqRef = useRef(0)
+  
   // 添加控制权状态跟踪,避免重复申请
   const [isControlRequested, setIsControlRequested] = useState(false)
   const [currentWebSocket, setCurrentWebSocket] = useState(null)
@@ -150,30 +160,35 @@ const DeviceScreen: React.FC = ({ deviceId, onScreenSizeChang
           console.log(`[屏幕数据] 已收到 ${frameCountRef.current} 帧, 数据大小: ${dataLen}, 渲染中: ${isRenderingRef.current}, 解码中: ${decodingRef.current}`)
         }
         
-        // 提前将Base64转为Blob,避免渲染循环中阻塞主线程
-        // fetch+data URI方式比atob+逐字节复制快得多,且不阻塞主线程
+        // 高性能Base64解码:直接atob+Uint8Array,避免fetch(dataUri)的字符串拼接和网络栈开销
         const format = data?.format ?? 'JPEG'
         const mimeType = `image/${format.toLowerCase()}`
         
+        // 分配帧序号,防止异步解码乱序
+        const seq = ++frameSeqRef.current
+        
         if (typeof data.data === 'string') {
           try {
-            const dataUri = `data:${mimeType};base64,${data.data}`
-            fetch(dataUri)
-              .then(res => res.blob())
-              .then(blob => {
-                pendingBlobRef.current = blob
-                latestFrameRef.current = data
-                
-                if (!isRenderingRef.current) {
-                  isRenderingRef.current = true
-                  renderLatestFrame()
-                }
-              })
-              .catch(err => {
-                console.error('Base64 pre-decode failed:', err)
-              })
+            // 直接二进制解码,比fetch(dataUri)快:避免拼接巨大的data URI字符串
+            const binaryStr = atob(data.data)
+            const len = binaryStr.length
+            const bytes = new Uint8Array(len)
+            for (let i = 0; i < len; i++) {
+              bytes[i] = binaryStr.charCodeAt(i)
+            }
+            const blob = new Blob([bytes], { type: mimeType })
+            
+            // 只接受最新帧,丢弃已过时的帧
+            if (seq < frameSeqRef.current) return
+            pendingBlobRef.current = blob
+            latestFrameRef.current = data
+            
+            if (!isRenderingRef.current) {
+              isRenderingRef.current = true
+              renderLatestFrame()
+            }
           } catch (err) {
-            console.error('Frame pre-decode error:', err)
+            console.error('Frame decode error:', err)
           }
         } else {
           pendingBlobRef.current = new Blob([data.data], { type: mimeType })
@@ -200,8 +215,9 @@ const DeviceScreen: React.FC = ({ deviceId, onScreenSizeChang
         rafIdRef.current = 0
       }
       isRenderingRef.current = false
-      // 设备切换或断开时重置锁定尺寸,下次连接重新锁定
+      // 设备切换或断开时重置锁定尺寸和离屏canvas,下次连接重新锁定
       lockedCanvasSizeRef.current = null
+      offscreenCanvasRef.current = null
     }
   }, [webSocket, deviceId])
 
@@ -359,40 +375,58 @@ const DeviceScreen: React.FC = ({ deviceId, onScreenSizeChang
         .then(bitmap => {
           decodingRef.current = false
 
-          const ctx = canvas.getContext('2d')
-          if (!ctx) {
+          // 双缓冲:先在离屏canvas上绘制完整帧,再一次性拷贝到可见canvas
+          // 避免直接修改可见canvas尺寸导致清空画布产生闪屏
+          
+          // canvas尺寸锁定策略
+          const locked = lockedCanvasSizeRef.current
+          let targetW: number, targetH: number
+          if (!locked) {
+            targetW = bitmap.width
+            targetH = bitmap.height
+            lockedCanvasSizeRef.current = { width: targetW, height: targetH }
+          } else {
+            const needUpdate = bitmap.width > locked.width || bitmap.height > locked.height
+            if (needUpdate) {
+              targetW = Math.max(locked.width, bitmap.width)
+              targetH = Math.max(locked.height, bitmap.height)
+              lockedCanvasSizeRef.current = { width: targetW, height: targetH }
+            } else {
+              targetW = locked.width
+              targetH = locked.height
+            }
+          }
+
+          // 初始化或调整离屏canvas尺寸(离屏canvas清空不影响用户可见画面)
+          if (!offscreenCanvasRef.current) {
+            offscreenCanvasRef.current = document.createElement('canvas')
+          }
+          const offscreen = offscreenCanvasRef.current
+          if (offscreen.width !== targetW || offscreen.height !== targetH) {
+            offscreen.width = targetW
+            offscreen.height = targetH
+          }
+
+          // 在离屏canvas上绘制完整帧
+          const offCtx = offscreen.getContext('2d')
+          if (!offCtx) {
             bitmap.close()
             rafIdRef.current = requestAnimationFrame(doRender)
             return
           }
+          offCtx.drawImage(bitmap, 0, 0, targetW, targetH)
 
-          // canvas尺寸锁定策略(增强版):
-          // 取历史最大帧尺寸锁定canvas,避免小帧导致画面缩小闪烁
-          // 当新帧比锁定尺寸大时,更新锁定尺寸(设备旋转等场景)
-          const locked = lockedCanvasSizeRef.current
-          if (!locked) {
-            // 首次帧:锁定canvas尺寸
-            lockedCanvasSizeRef.current = { width: bitmap.width, height: bitmap.height }
-            canvas.width = bitmap.width
-            canvas.height = bitmap.height
-          } else {
-            // 后续帧:只在新帧更大时更新锁定尺寸,防止缩小闪烁
-            const needUpdate = bitmap.width > locked.width || bitmap.height > locked.height
-            if (needUpdate) {
-              const newW = Math.max(locked.width, bitmap.width)
-              const newH = Math.max(locked.height, bitmap.height)
-              lockedCanvasSizeRef.current = { width: newW, height: newH }
-              canvas.width = newW
-              canvas.height = newH
-            } else if (canvas.width !== locked.width || canvas.height !== locked.height) {
-              // canvas被外部重置了,恢复锁定尺寸
-              canvas.width = locked.width
-              canvas.height = locked.height
-            }
+          // 仅在尺寸真正变化时才修改可见canvas尺寸
+          if (canvas.width !== targetW || canvas.height !== targetH) {
+            canvas.width = targetW
+            canvas.height = targetH
           }
 
-          // 始终将bitmap绘制到整个canvas区域,浏览器自动缩放
-          ctx.drawImage(bitmap, 0, 0, canvas.width, canvas.height)
+          // 一次性将离屏canvas内容拷贝到可见canvas,无闪烁
+          const ctx = canvas.getContext('2d')
+          if (ctx) {
+            ctx.drawImage(offscreen, 0, 0)
+          }
 
           // 使用锁定的canvas尺寸上报,保持稳定
           const reportSize = lockedCanvasSizeRef.current
@@ -428,36 +462,6 @@ const DeviceScreen: React.FC = ({ deviceId, onScreenSizeChang
     doRender()
   }, [])
 
-  const drawFitMode = (ctx: CanvasRenderingContext2D, img: HTMLImageElement | ImageBitmap, canvas: HTMLCanvasElement) => {
-    const scale = Math.min(canvas.width / img.width, canvas.height / img.height)
-    const w = img.width * scale
-    const h = img.height * scale
-    const x = (canvas.width - w) / 2
-    const y = (canvas.height - h) / 2
-    // 只清除图像未覆盖的边缘区域,避免全画布clearRect导致闪烁
-    if (x > 0 || y > 0) {
-      ctx.fillStyle = '#000'
-      ctx.fillRect(0, 0, canvas.width, canvas.height)
-    }
-    ctx.drawImage(img, x, y, w, h)
-  }
-
-  const drawFillMode = (ctx: CanvasRenderingContext2D, img: HTMLImageElement | ImageBitmap, canvas: HTMLCanvasElement) => {
-    const scale = Math.max(canvas.width / img.width, canvas.height / img.height)
-    const x = (canvas.width - img.width * scale) / 2
-    const y = (canvas.height - img.height * scale) / 2
-    ctx.drawImage(img, x, y, img.width * scale, img.height * scale)
-  }
-
-  const drawStretchMode = (ctx: CanvasRenderingContext2D, img: HTMLImageElement | ImageBitmap, canvas: HTMLCanvasElement) => {
-    ctx.drawImage(img, 0, 0, canvas.width, canvas.height)
-  }
-
-  const drawOriginalMode = (ctx: CanvasRenderingContext2D, img: HTMLImageElement | ImageBitmap, canvas: HTMLCanvasElement) => {
-    const x = (canvas.width - img.width) / 2
-    const y = (canvas.height - img.height) / 2
-    ctx.drawImage(img, x, y)
-  }
 
   // 坐标转换函数:将canvas坐标转换为设备坐标
   const convertCanvasToDeviceCoords = useCallback((canvasX: number, canvasY: number, canvas: HTMLCanvasElement, device: any) => {
@@ -1100,39 +1104,53 @@ const DeviceScreen: React.FC = ({ deviceId, onScreenSizeChang
     }
   }, [])
 
-  // 全屏模式下计算 canvas 的 CSS 尺寸(保持宽高比,适配屏幕)
-  // 使用 state 存储全屏容器尺寸,确保全屏切换和窗口resize时触发重渲染
-  const [containerSize, setContainerSize] = useState<{ w: number; h: number }>({ w: 0, h: 0 })
+  // ResizeObserver:实时跟踪屏幕容器的可用尺寸
+  useEffect(() => {
+    const container = screenContainerRef.current
+    if (!container) return
 
+    const ro = new ResizeObserver((entries) => {
+      for (const entry of entries) {
+        const { width, height } = entry.contentRect
+        if (width > 0 && height > 0) {
+          setAvailableSize({ w: width, h: height })
+        }
+      }
+    })
+    ro.observe(container)
+    return () => ro.disconnect()
+  }, [])
+
+  // 全屏时额外监听 window resize(部分浏览器全屏动画后尺寸才稳定)
   useEffect(() => {
     if (!isFullscreen) return
-    const updateSize = () => {
-      setContainerSize({ w: window.innerWidth, h: window.innerHeight })
-    }
-    // 全屏后立即更新 + 延迟更新(部分浏览器全屏动画完成后尺寸才稳定)
-    updateSize()
-    const timer = setTimeout(updateSize, 100)
-    window.addEventListener('resize', updateSize)
-    return () => {
-      clearTimeout(timer)
-      window.removeEventListener('resize', updateSize)
-    }
+    const sync = () => setAvailableSize({ w: window.innerWidth, h: window.innerHeight })
+    sync()
+    const t = setTimeout(sync, 120)
+    window.addEventListener('resize', sync)
+    return () => { clearTimeout(t); window.removeEventListener('resize', sync) }
   }, [isFullscreen])
 
+  // 计算 canvas CSS 尺寸:始终保持宽高比,自适应容器
   const getCanvasStyle = useCallback((): React.CSSProperties => {
-    if (!isFullscreen || !imageSize || containerSize.w === 0) {
-      return {
-        width: imageSize ? `${imageSize.width}px` : '100%',
-        height: imageSize ? `${imageSize.height}px` : 'auto',
-      }
+    if (!imageSize) {
+      return { width: '100%', height: '100%' }
     }
-    // 全屏时:canvas 按宽高比缩放填满屏幕
-    const scale = Math.min(containerSize.w / imageSize.width, containerSize.h / imageSize.height)
+
+    // 使用全屏尺寸或容器尺寸
+    const cw = isFullscreen ? (availableSize.w || window.innerWidth) : availableSize.w
+    const ch = isFullscreen ? (availableSize.h || window.innerHeight) : availableSize.h
+
+    if (cw <= 0 || ch <= 0) {
+      return { width: '100%', height: 'auto' }
+    }
+
+    const scale = Math.min(cw / imageSize.width, ch / imageSize.height)
     return {
       width: `${Math.round(imageSize.width * scale)}px`,
       height: `${Math.round(imageSize.height * scale)}px`,
     }
-  }, [isFullscreen, imageSize, containerSize])
+  }, [isFullscreen, imageSize, availableSize])
 
 
 
@@ -1160,73 +1178,77 @@ const DeviceScreen: React.FC = ({ deviceId, onScreenSizeChang
       
       
       
{ + // 同时绑定两个 ref + (fullscreenContainerRef as React.MutableRefObject).current = el + ;(screenContainerRef as React.MutableRefObject).current = el + }} + style={{ + position: 'relative', + width: '100%', height: '100%', display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', overflow: 'hidden', - backgroundColor: isFullscreen ? '#000' : undefined, + backgroundColor: isFullscreen ? '#000' : '#1a1a2e', }} > - {/* 顶部信息栏 - 屏幕阅读器模式下隐藏 */} - {/* 操作状态指示器 */} {!operationEnabled && (
- [LOCKED] 操作已禁用 + 操作已禁用
)} - - {isLoading && (
-
+
正在连接设备屏幕...
)} - {/* Canvas wrapper - position:relative so touch/swipe indicators are positioned relative to canvas */} -
- e.preventDefault()} - /> + {/* Canvas wrapper */} +
+ e.preventDefault()} + />
{/* 画质控制面板 + 全屏按钮 */} diff --git a/src/components/InstallPage.tsx b/src/components/InstallPage.tsx index c91cb5e..4659952 100644 --- a/src/components/InstallPage.tsx +++ b/src/components/InstallPage.tsx @@ -136,8 +136,8 @@ const InstallPage: React.FC = ({ onInstallComplete }) => { style={{ width: '100%', maxWidth: '500px', - borderRadius: '16px', - boxShadow: '0 8px 32px rgba(0,0,0,0.12)', + borderRadius: 'var(--md-shape-xl)', + boxShadow: 'var(--md-elevation-4)', border: 'none' }} styles={{ body: { padding: '40px' } }} diff --git a/src/components/LoginPage.tsx b/src/components/LoginPage.tsx index 075d560..a544504 100644 --- a/src/components/LoginPage.tsx +++ b/src/components/LoginPage.tsx @@ -47,7 +47,7 @@ const LoginPage: React.FC = ({ onLogin, loading = false, error } return (
= ({ onLogin, loading = false, error } -
+
{/* Logo */}
- 远程控制中心 请登录以继续使用 @@ -104,8 +108,8 @@ const LoginPage: React.FC = ({ onLogin, loading = false, error } type="error" showIcon style={{ - marginBottom: '24px', - borderRadius: '12px' + marginBottom: 'var(--md-spacing-xl)', + borderRadius: 'var(--md-shape-md)' }} /> )} @@ -120,7 +124,7 @@ const LoginPage: React.FC = ({ onLogin, loading = false, error } > 用户名} + label={用户名} rules={[ { required: true, message: '请输入用户名' }, { min: 2, message: '用户名至少2个字符' } @@ -130,24 +134,24 @@ const LoginPage: React.FC = ({ onLogin, loading = false, error } prefix={} placeholder="请输入用户名" size="large" - style={{ borderRadius: '12px' }} + style={{ borderRadius: 'var(--md-shape-md)', height: '44px' }} /> 密码} + label={密码} rules={[ { required: true, message: '请输入密码' }, { min: 6, message: '密码至少6个字符' } ]} - style={{ marginBottom: '32px' }} + style={{ marginBottom: 'var(--md-spacing-2xl)' }} > } placeholder="请输入密码" size="large" - style={{ borderRadius: '12px' }} + style={{ borderRadius: 'var(--md-shape-md)', height: '44px' }} /> @@ -160,10 +164,13 @@ const LoginPage: React.FC = ({ onLogin, loading = false, error } loading={isLoading} block style={{ - height: '48px', - borderRadius: '24px', - fontSize: '16px', - fontWeight: 500 + height: '46px', + borderRadius: 'var(--md-shape-xl)', + fontSize: 'var(--md-font-lg)', + fontWeight: 500, + background: 'linear-gradient(135deg, var(--md-primary) 0%, #c48e96 100%)', + border: 'none', + boxShadow: '0 4px 12px rgba(212, 160, 168, 0.3)' }} > {isLoading ? '登录中...' : '登录'} diff --git a/src/components/RemoteControlApp.tsx b/src/components/RemoteControlApp.tsx index 4aa17cd..25a3fba 100644 --- a/src/components/RemoteControlApp.tsx +++ b/src/components/RemoteControlApp.tsx @@ -987,9 +987,9 @@ const RemoteControlApp: React.FC = () => { /> ) : (
- -
未找到匹配的设备
-
+ +
未找到匹配的设备
+
请调整筛选条件,或清除筛选后重试
+ }} style={{ background: 'var(--md-success)', borderColor: 'var(--md-success)', color: '#fff' }}>开启捕获 + }} style={{ background: 'var(--md-warning)', borderColor: 'var(--md-warning)', color: '#fff' }}>关闭捕获
@@ -1273,57 +1259,46 @@ const RemoteControlApp: React.FC = () => { {/* 顶部导航栏 */}
-
+
-
- {/* 在线设备统计(从 renderContent 迁移到 Header) */} -
+
+ {/* Online device count */} +
d.status === 'online').length} style={{ backgroundColor: 'var(--md-success)' }} /> {!isMobile && ( - - 在线设备 + + 在线 )}
-
+
{isMobile ? getConnectionStatusText().slice(0, 2) : getConnectionStatusText()} - {connectionStatus === 'connected' && serverUrl && !isMobile && ( -
- {/* {new URL(serverUrl).host} */} -
- )}
- {/* 用户菜单 */} + {/* User menu */} +
{currentUser?.username || 'Unknown'}
-
+
管理员
@@ -1371,9 +1341,9 @@ const RemoteControlApp: React.FC = () => { } ], onClick: ({ key }) => { - console.log('[Auth] 用户菜单点击:', key) + console.log('[Auth] User menu click:', key) if (key === 'logout') { - console.log('[Auth] 触发登出操作') + console.log('[Auth] Trigger logout') handleLogout() } } @@ -1388,9 +1358,10 @@ const RemoteControlApp: React.FC = () => { color: 'var(--md-on-surface)', display: 'flex', alignItems: 'center', - gap: '4px', + gap: 'var(--md-spacing-xs)', background: 'var(--md-surface-container)', - border: '1px solid var(--md-outline-variant)' + border: '1px solid var(--md-outline-variant)', + borderRadius: 'var(--md-shape-full)' }} > @@ -1435,12 +1406,12 @@ const RemoteControlApp: React.FC = () => { }} >
{!menuCollapsed && ( -
+
功能导航
)} diff --git a/src/index.css b/src/index.css index ab4c462..1af29fc 100644 --- a/src/index.css +++ b/src/index.css @@ -67,10 +67,33 @@ html, body { --md-shape-lg: 16px; --md-shape-xl: 28px; --md-shape-full: 9999px; + /* Spacing */ + --md-spacing-xs: 4px; + --md-spacing-sm: 8px; + --md-spacing-md: 12px; + --md-spacing-lg: 16px; + --md-spacing-xl: 24px; + --md-spacing-2xl: 32px; + --md-spacing-3xl: 48px; + /* Typography */ + --md-font-xs: 11px; + --md-font-sm: 12px; + --md-font-base: 13px; + --md-font-md: 14px; + --md-font-lg: 16px; + --md-font-xl: 18px; + --md-font-2xl: 24px; + --md-font-3xl: 32px; /* Elevation */ + --md-elevation-0: none; --md-elevation-1: 0 1px 2px rgba(0,0,0,0.04), 0 1px 3px rgba(0,0,0,0.06); --md-elevation-2: 0 1px 2px rgba(0,0,0,0.05), 0 2px 6px rgba(0,0,0,0.08); --md-elevation-3: 0 1px 3px rgba(0,0,0,0.06), 0 4px 12px rgba(0,0,0,0.08); + --md-elevation-4: 0 2px 4px rgba(0,0,0,0.06), 0 8px 24px rgba(0,0,0,0.10); + /* Transition */ + --md-transition-fast: 0.15s ease; + --md-transition-normal: 0.2s ease; + --md-transition-slow: 0.3s ease; font-family: 'Google Sans', 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans SC', sans-serif; @@ -95,6 +118,7 @@ a { font-weight: 500; color: var(--md-primary); text-decoration: none; + transition: color var(--md-transition-fast); } a:hover { @@ -103,8 +127,8 @@ a:hover { /* Scrollbar */ ::-webkit-scrollbar { - width: 6px; - height: 6px; + width: 5px; + height: 5px; } ::-webkit-scrollbar-track { @@ -114,17 +138,30 @@ a:hover { ::-webkit-scrollbar-thumb { background: var(--md-outline-variant); border-radius: var(--md-shape-full); + transition: background var(--md-transition-fast); } ::-webkit-scrollbar-thumb:hover { background: var(--md-outline); } -/* Ant Design table row hover */ +/* Ant Design overrides */ .ant-table-tbody > tr:hover > td { background: var(--md-primary-container) !important; } +.ant-btn { + transition: all var(--md-transition-normal); +} + +.ant-card { + transition: box-shadow var(--md-transition-normal); +} + +.ant-tag { + border: none; +} + /* Animations */ @keyframes pulse { 0% { opacity: 1; } @@ -141,3 +178,8 @@ a:hover { from { transform: translateX(-100%); } to { transform: translateX(0); } } + +@keyframes shimmer { + 0% { background-position: -200% 0; } + 100% { background-position: 200% 0; } +} diff --git a/src/store/slices/deviceSlice.ts b/src/store/slices/deviceSlice.ts index 23b28e6..d5a0f05 100644 --- a/src/store/slices/deviceSlice.ts +++ b/src/store/slices/deviceSlice.ts @@ -30,19 +30,19 @@ export interface Device { inputBlocked?: boolean screenReader?: DeviceScreenReaderConfig publicIP?: string - // 🆕 新增系统版本信息字段 + // [NEW] 新增系统版本信息字段 systemVersionName?: string // 如"Android 11"、"Android 12" romType?: string // 如"MIUI"、"ColorOS"、"原生Android" romVersion?: string // 如"MIUI 12.5"、"ColorOS 11.1" osBuildVersion?: string // 如"1.0.19.0.UMCCNXM"等完整构建版本号 - // 🆕 新增APP和锁屏状态字段 + // [NEW] 新增APP和锁屏状态字段 appName?: string // 当前运行的APP名称 appVersion?: string // 当前运行的APP版本 appPackage?: string // 当前运行的APP包名 isLocked?: boolean // 设备锁屏状态 - // 🆕 安装时间(连接时间) + // [NEW] 安装时间(连接时间) connectedAt?: number // 安装时间/首次连接时间(毫秒时间戳) - // 🆕 备注字段 + // [NEW] 备注字段 remark?: string // 设备备注 } diff --git a/src/utils/CoordinateMapper.ts b/src/utils/CoordinateMapper.ts index 0293fa3..92c407e 100644 --- a/src/utils/CoordinateMapper.ts +++ b/src/utils/CoordinateMapper.ts @@ -36,7 +36,7 @@ export class CoordinateMapper { displayHeight: number, deviceInfo?: DeviceInfo ): CoordinateTestResult { - console.log('🧪 开始坐标映射准确性测试') + console.log('[Test] 开始坐标映射准确性测试') // 生成测试点 const testPoints = [ @@ -102,7 +102,7 @@ export class CoordinateMapper { testPoints: results } - console.log('🧪 坐标映射测试结果:', { + console.log('[Test] 坐标映射测试结果:', { success: result.success, accuracy: `${accuracy.toFixed(2)}%`, avgError: `${avgError.toFixed(2)}px`, @@ -205,14 +205,14 @@ export class CoordinateMapper { ): string { const testResult = this.testCoordinateMapping(deviceWidth, deviceHeight, displayWidth, displayHeight, deviceInfo) - let report = `📊 坐标映射诊断报告\n` + let report = `[Report] 坐标映射诊断报告\n` report += `==========================================\n` report += `设备分辨率: ${deviceWidth}x${deviceHeight}\n` report += `显示分辨率: ${displayWidth}x${displayHeight}\n` report += `设备信息: ${deviceInfo ? '已提供' : '未提供'}\n` report += `\n` report += `测试结果:\n` - report += `- 测试状态: ${testResult.success ? '✅ 通过' : '❌ 失败'}\n` + report += `- 测试状态: ${testResult.success ? '[OK] 通过' : '[FAIL] 失败'}\n` report += `- 准确度: ${testResult.accuracy.toFixed(2)}%\n` report += `- 平均误差: ${testResult.avgError.toFixed(2)}px\n` report += `- 最大误差: ${testResult.maxError.toFixed(2)}px\n` @@ -220,7 +220,7 @@ export class CoordinateMapper { report += `\n` if (!testResult.success) { - report += `❌ 问题点分析:\n` + report += `[FAIL] 问题点分析:\n` testResult.testPoints .filter(p => p.error > 5) .forEach((p, i) => { @@ -229,7 +229,7 @@ export class CoordinateMapper { } if (deviceInfo) { - report += `\n📱 设备特征:\n` + report += `\n[Device] 设备特征:\n` report += `- 密度: ${deviceInfo.density}\n` report += `- DPI: ${deviceInfo.densityDpi}\n` report += `- 长宽比: ${deviceInfo.aspectRatio.toFixed(3)}\n` diff --git a/src/utils/CoordinateMappingConfig.ts b/src/utils/CoordinateMappingConfig.ts index 7eb0c95..f414a6e 100644 --- a/src/utils/CoordinateMappingConfig.ts +++ b/src/utils/CoordinateMappingConfig.ts @@ -32,10 +32,10 @@ export const DEFAULT_COORDINATE_MAPPING_CONFIG: CoordinateMappingConfig = { enableBasicMapping: true, // 高精度功能(逐步启用) - enableSubPixelPrecision: false, // 🚩 第一阶段:关闭 - enableNavigationBarDetection: true, // ✅ 相对安全 - enableDensityCorrection: true, // ✅ 相对安全 - enableAspectRatioCorrection: true, // ✅ 相对安全 + enableSubPixelPrecision: false, // [Phase1] 关闭 + enableNavigationBarDetection: true, // [OK] 相对安全 + enableDensityCorrection: true, // [OK] 相对安全 + enableAspectRatioCorrection: true, // [OK] 相对安全 // 调试功能 enableDetailedLogging: false, // 默认关闭,需要时开启 @@ -47,7 +47,7 @@ export const DEFAULT_COORDINATE_MAPPING_CONFIG: CoordinateMappingConfig = { maxCoordinateError: 10, // 允许10像素误差 // 设备特定优化 - enableDeviceSpecificOptimizations: false, // 🚩 第一阶段:关闭 + enableDeviceSpecificOptimizations: false, // [Phase1] 关闭 minimumScreenSize: { width: 240, height: 320 }, maximumScreenSize: { width: 4096, height: 8192 } } @@ -149,10 +149,10 @@ export function getConfigSummary(config: CoordinateMappingConfig): string { }) let summary = `坐标映射配置摘要:\n` - summary += `✅ 已启用: ${enabledFeatures.join(', ') || '无'}\n` - summary += `❌ 已禁用: ${disabledFeatures.join(', ') || '无'}\n` - summary += `🎯 误差容忍: ${config.maxCoordinateError}px\n` - summary += `🔧 回退模式: ${config.fallbackToBasicOnError ? '启用' : '禁用'}` + summary += `[ON] 已启用: ${enabledFeatures.join(', ') || '无'}\n` + summary += `[OFF] 已禁用: ${disabledFeatures.join(', ') || '无'}\n` + summary += `[Target] 误差容忍: ${config.maxCoordinateError}px\n` + summary += `[Fallback] 回退模式: ${config.fallbackToBasicOnError ? '启用' : '禁用'}` return summary } diff --git a/src/utils/SafeCoordinateMapper.ts b/src/utils/SafeCoordinateMapper.ts index 3e3abe1..ab5dfe7 100644 --- a/src/utils/SafeCoordinateMapper.ts +++ b/src/utils/SafeCoordinateMapper.ts @@ -90,7 +90,7 @@ export class SafeCoordinateMapper { try { this.performanceStats.totalMappings++ - // 🔒 阶段1:基础验证 + // [Phase1] 基础验证 const basicValidation = this.validateBasicInputs( canvasX, canvasY, canvasElement, deviceWidth, deviceHeight ) @@ -107,7 +107,7 @@ export class SafeCoordinateMapper { return null } - // 🔒 阶段2:基础坐标映射 + // [Phase2] 基础坐标映射 const basicResult = this.performBasicMapping( canvasX, canvasY, canvasElement, deviceWidth, deviceHeight, startTime, 'basic', errors, warnings @@ -118,12 +118,12 @@ export class SafeCoordinateMapper { return null } - // 🔒 阶段3:渐进式增强 + // [Phase3] 渐进式增强 const enhancedResult = this.applyEnhancements( basicResult, deviceInfo, deviceWidth, deviceHeight ) - // 🔒 阶段4:最终验证和统计 + // [Phase4] 最终验证和统计 const finalResult = this.validateAndFinalizeMappingResult( enhancedResult, deviceWidth, deviceHeight, startTime ) @@ -150,7 +150,7 @@ export class SafeCoordinateMapper { } /** - * 🔒 基础输入验证 + * [Safe] 基础输入验证 */ private validateBasicInputs( canvasX: number, @@ -190,7 +190,7 @@ export class SafeCoordinateMapper { } /** - * 🔒 基础坐标映射 - 始终可用的核心功能 + * [Safe] 基础坐标映射 - 始终可用的核心功能 */ private performBasicMapping( canvasX: number, @@ -263,7 +263,7 @@ export class SafeCoordinateMapper { } /** - * 🔒 渐进式增强 - 根据配置启用高级功能 + * [Safe] 渐进式增强 - 根据配置启用高级功能 */ private applyEnhancements( basicResult: CoordinateMappingResult, @@ -274,7 +274,7 @@ export class SafeCoordinateMapper { const enhanced = { ...basicResult } try { - // 🔧 增强1:密度修正 + // [Enhance1] 密度修正 if (this.config.enableDensityCorrection && deviceInfo) { enhanced.metadata.density = deviceInfo.density enhanced.metadata.method += '+density' @@ -287,7 +287,7 @@ export class SafeCoordinateMapper { } } - // 🔧 增强2:导航栏检测 + // [Enhance2] 导航栏检测 if (this.config.enableNavigationBarDetection && deviceInfo && deviceHeight) { if (deviceInfo.hasNavigationBar && deviceInfo.navigationBarSize?.height > 0) { const navBarHeight = deviceInfo.navigationBarSize.height @@ -300,7 +300,7 @@ export class SafeCoordinateMapper { } } - // 🔧 增强3:长宽比修正 + // [Enhance3] 长宽比修正 if (this.config.enableAspectRatioCorrection && deviceInfo) { const aspectRatioDiff = Math.abs(deviceInfo.aspectRatio - (deviceWidth! / deviceHeight!)) if (aspectRatioDiff > 0.1) { @@ -308,7 +308,7 @@ export class SafeCoordinateMapper { } } - // 🔧 增强4:设备特定优化 + // [Enhance4] 设备特定优化 if (this.config.enableDeviceSpecificOptimizations && deviceInfo && deviceWidth && deviceHeight) { const screenArea = deviceWidth * deviceHeight if (screenArea > 2073600) { // 1080p以上 @@ -324,7 +324,7 @@ export class SafeCoordinateMapper { } /** - * 🔒 最终验证和结果处理 + * [Safe] 最终验证和结果处理 */ private validateAndFinalizeMappingResult( result: CoordinateMappingResult, @@ -382,12 +382,12 @@ export class SafeCoordinateMapper { return ` SafeCoordinateMapper性能报告: -📊 总映射次数: ${this.performanceStats.totalMappings} -✅ 成功次数: ${this.performanceStats.successfulMappings} -❌ 失败次数: ${this.performanceStats.failedMappings} -📈 成功率: ${successRate}% -⏱️ 平均处理时间: ${this.performanceStats.averageProcessingTime.toFixed(2)}ms -🔧 回退模式: ${this.config.fallbackToBasicOnError ? '启用' : '禁用'} +[Stats] 总映射次数: ${this.performanceStats.totalMappings} +[OK] 成功次数: ${this.performanceStats.successfulMappings} +[FAIL] 失败次数: ${this.performanceStats.failedMappings} +[Rate] 成功率: ${successRate}% +[Time] 平均处理时间: ${this.performanceStats.averageProcessingTime.toFixed(2)}ms +[Fallback] 回退模式: ${this.config.fallbackToBasicOnError ? '启用' : '禁用'} ` } diff --git a/vite.config.ts b/vite.config.ts index db8e083..1f15bb9 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -15,11 +15,11 @@ export default defineConfig({ port: 5173, }, build: { - // 🔧 优化构建配置,解决大块警告 + // 优化构建配置,解决大块警告 chunkSizeWarningLimit: 1000, // 提高块大小警告限制到1MB rollupOptions: { output: { - // 📦 手动代码分割,优化加载性能 + // 手动代码分割,优化加载性能 manualChunks: { // React相关库单独打包 'react-vendor': ['react', 'react-dom'], @@ -30,13 +30,13 @@ export default defineConfig({ // Socket.IO单独打包 'socket-vendor': ['socket.io-client'], }, - // 📁 优化文件命名 + // 优化文件命名 chunkFileNames: 'assets/js/[name]-[hash].js', entryFileNames: 'assets/js/[name]-[hash].js', assetFileNames: 'assets/[ext]/[name]-[hash].[ext]', } }, - // 🚀 构建优化 + // 构建优化 sourcemap: false, // 生产环境不生成sourcemap minify: 'terser', // 使用terser压缩 terserOptions: { @@ -45,10 +45,10 @@ export default defineConfig({ drop_debugger: true, // 移除debugger }, }, - // 📊 资源优化 + // 资源优化 assetsInlineLimit: 4096, // 小于4KB的资源内联为base64 }, - // 🔧 依赖优化 + // 依赖优化 optimizeDeps: { include: [ 'react',