<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>实时手部检测控制系统</title>
    <script src="https://cdn.socket.io/4.0.0/socket.io.min.js"></script>
    <style>
        body {
            font-family: Arial, sans-serif;
            margin: 0;
            padding: 20px;
            background-color: #f0f0f0;
        }
        .container {
            max-width: 1200px;
            margin: 0 auto;
            background: white;
            padding: 20px;
            border-radius: 10px;
            box-shadow: 0 2px 10px rgba(0,0,0,0.1);
        }
        h1 {
            text-align: center;
            color: #333;
            margin-bottom: 30px;
        }
        .main-content {
            display: grid;
            grid-template-columns: 2fr 1fr;
            gap: 20px;
            margin-bottom: 20px;
        }
        .video-section {
            background: #000;
            border-radius: 10px;
            padding: 10px;
            min-height: 480px;
            display: flex;
            align-items: center;
            justify-content: center;
        }
        .video-container {
            position: relative;
            width: 100%;
            height: 100%;
            max-width: 640px;
            max-height: 480px;
        }
        #videoPreview {
            width: 100%;
            height: 100%;
            object-fit: contain;
            border-radius: 5px;
        }
        .no-video {
            color: #999;
            font-size: 18px;
            text-align: center;
        }
        .control-panel {
            background: #f8f9fa;
            padding: 20px;
            border-radius: 10px;
            border: 1px solid #e0e0e0;
        }
        .status-section {
            margin-bottom: 20px;
        }
        .status-item {
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 10px;
            padding: 8px 12px;
            background: white;
            border-radius: 5px;
            border: 1px solid #ddd;
        }
        .status-label {
            font-weight: bold;
            color: #333;
        }
        .status-value {
            color: #007bff;
            font-family: monospace;
        }
        .angle-display {
            display: grid;
            grid-template-columns: 1fr 1fr 1fr;
            gap: 10px;
            margin-bottom: 20px;
        }
        .angle-card {
            background: white;
            padding: 15px;
            border-radius: 8px;
            border: 2px solid #ddd;
            text-align: center;
        }
        .angle-card.x-axis {
            border-color: #ff4757;
        }
        .angle-card.y-axis {
            border-color: #2ed573;
        }
        .angle-card.z-axis {
            border-color: #3742fa;
        }
        .angle-label {
            font-size: 14px;
            font-weight: bold;
            margin-bottom: 5px;
        }
        .angle-value {
            font-size: 24px;
            font-weight: bold;
            font-family: monospace;
        }
        .action-display {
            background: white;
            padding: 15px;
            border-radius: 8px;
            border: 1px solid #ddd;
            margin-bottom: 20px;
        }
        .action-title {
            font-weight: bold;
            margin-bottom: 10px;
            color: #333;
        }
        .action-value {
            font-size: 18px;
            padding: 8px 12px;
            background: #e3f2fd;
            border-radius: 5px;
            color: #1976d2;
            font-family: monospace;
        }
        .grip-status {
            display: flex;
            align-items: center;
            justify-content: space-between;
            padding: 10px;
            background: white;
            border-radius: 5px;
            border: 1px solid #ddd;
        }
        .grip-indicator {
            width: 20px;
            height: 20px;
            border-radius: 50%;
            background: #ccc;
            transition: background 0.3s ease;
        }
        .grip-indicator.active {
            background: #ff6b6b;
        }
        .connection-status {
            display: flex;
            align-items: center;
            gap: 10px;
            padding: 10px;
            background: white;
            border-radius: 5px;
            border: 1px solid #ddd;
            margin-bottom: 20px;
        }
        .connection-dot {
            width: 12px;
            height: 12px;
            border-radius: 50%;
            background: #ccc;
            transition: background 0.3s ease;
        }
        .connection-dot.connected {
            background: #2ed573;
        }
        .test-controls {
            margin-top: 20px;
        }
        .video-selector {
            margin-bottom: 15px;
        }
        .video-select {
            width: 100%;
            padding: 10px;
            border: 1px solid #ddd;
            border-radius: 5px;
            font-size: 14px;
            background: white;
            margin-bottom: 10px;
        }
        .video-select:focus {
            outline: none;
            border-color: #007bff;
        }
        .test-button {
            width: 100%;
            padding: 12px;
            background: #007bff;
            color: white;
            border: none;
            border-radius: 5px;
            font-size: 16px;
            cursor: pointer;
            margin-bottom: 10px;
        }
        .test-button:hover {
            background: #0056b3;
        }
        .test-button:disabled {
            background: #ccc;
            cursor: not-allowed;
        }
        .log-section {
            background: #f8f9fa;
            padding: 20px;
            border-radius: 10px;
            border: 1px solid #e0e0e0;
        }
        .log-title {
            font-weight: bold;
            margin-bottom: 10px;
            color: #333;
        }
        .log-container {
            background: #000;
            color: #0f0;
            padding: 15px;
            border-radius: 5px;
            font-family: monospace;
            font-size: 12px;
            height: 200px;
            overflow-y: auto;
        }
        .log-entry {
            margin-bottom: 5px;
        }
        .log-timestamp {
            color: #888;
        }
        .fps-display {
            font-size: 14px;
            color: #666;
            text-align: center;
            margin-top: 10px;
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>🤖 实时手部检测控制系统</h1>
        
        <div class="main-content">
            <div class="video-section">
                <div class="video-container">
                    <img id="videoPreview" style="display:none;" alt="视频预览">
                    <div id="noVideo" class="no-video">
                        等待视频流...
                    </div>
                </div>
            </div>
            
            <div class="control-panel">
                <div class="connection-status">
                    <div id="connectionDot" class="connection-dot"></div>
                    <span id="connectionStatus">连接中...</span>
                </div>
                
                <div class="status-section">
                    <div class="status-item">
                        <span class="status-label">FPS:</span>
                        <span id="fpsValue" class="status-value">0</span>
                    </div>
                    <div class="status-item">
                        <span class="status-label">速度:</span>
                        <span id="speedValue" class="status-value">5</span>
                    </div>
                </div>
                
                <div class="angle-display">
                    <div class="angle-card x-axis">
                        <div class="angle-label" style="color: #ff4757;">X轴 (左右)</div>
                        <div id="xAngle" class="angle-value" style="color: #ff4757;">90°</div>
                    </div>
                    <div class="angle-card y-axis">
                        <div class="angle-label" style="color: #2ed573;">Y轴 (上下)</div>
                        <div id="yAngle" class="angle-value" style="color: #2ed573;">90°</div>
                    </div>
                    <div class="angle-card z-axis">
                        <div class="angle-label" style="color: #3742fa;">Z轴 (前后)</div>
                        <div id="zAngle" class="angle-value" style="color: #3742fa;">90°</div>
                    </div>
                </div>
                
                <div class="action-display">
                    <div class="action-title">当前动作:</div>
                    <div id="actionValue" class="action-value">none</div>
                </div>
                
                <div class="grip-status">
                    <span>抓取状态:</span>
                    <div class="grip-indicator" id="gripIndicator"></div>
                </div>
                
                <div class="test-controls">
                    <div class="video-selector">
                        <label for="videoSelect" style="font-size: 14px; font-weight: bold; margin-bottom: 8px; display: block;">选择测试视频:</label>
                        <select id="videoSelect" class="video-select">
                            <option value="">加载中...</option>
                        </select>
                    </div>
                    <button id="testButton" class="test-button">开始视频测试</button>
                    <button id="refreshButton" class="test-button" style="background: #28a745; margin-top: 5px;">刷新视频列表</button>
                    <div style="font-size: 12px; color: #666; margin-top: 5px; text-align: center;">
                        选择本地视频文件进行检测
                    </div>
                </div>
            </div>
        </div>
        
        <div class="log-section">
            <div class="log-title">系统日志</div>
            <div class="log-container" id="logContainer"></div>
        </div>
    </div>

    <script>
        class HandDetectionClient {
            constructor() {
                this.socket = io();
                this.isConnected = false;
                this.setupSocketEvents();
                this.setupUI();
            }
            
            setupSocketEvents() {
                this.socket.on('connect', () => {
                    this.isConnected = true;
                    this.updateConnectionStatus('已连接', true);
                    this.log('WebSocket连接已建立');
                    
                    // 注册为web预览客户端
                    this.socket.emit('register_client', {
                        type: 'web_preview'
                    });
                });
                
                this.socket.on('disconnect', () => {
                    this.isConnected = false;
                    this.updateConnectionStatus('连接断开', false);
                    this.log('WebSocket连接已断开');
                });
                
                this.socket.on('status', (data) => {
                    this.log(`服务器状态: ${data.message}`);
                });
                
                this.socket.on('registration_success', (data) => {
                    this.log(`客户端注册成功: ${data.type}`);
                });
                
                this.socket.on('detection_results', (data) => {
                    this.updateDetectionResults(data);
                });
                
                this.socket.on('error', (data) => {
                    this.log(`错误: ${data.message}`, 'error');
                });
                
                this.socket.on('pong', (data) => {
                    // 处理ping响应
                });
                
                this.socket.on('test_started', (data) => {
                    this.log(`✅ ${data.message}`, 'info');
                });
                
                this.socket.on('test_error', (data) => {
                    this.log(`❌ ${data.message}`, 'error');
                    if (data.help) {
                        this.log(`💡 ${data.help}`, 'info');
                    }
                });
                
                this.socket.on('video_list', (data) => {
                    this.updateVideoList(data.videos);
                });
            }
            
            setupUI() {
                document.getElementById('testButton').addEventListener('click', () => {
                    this.startLocalTest();
                });
                
                document.getElementById('refreshButton').addEventListener('click', () => {
                    this.refreshVideoList();
                });
                
                // 请求视频列表
                this.refreshVideoList();
                
                // 定期发送ping
                setInterval(() => {
                    if (this.isConnected) {
                        this.socket.emit('ping');
                    }
                }, 5000);
            }
            
            updateConnectionStatus(status, connected) {
                const statusElement = document.getElementById('connectionStatus');
                const dotElement = document.getElementById('connectionDot');
                
                statusElement.textContent = status;
                if (connected) {
                    dotElement.classList.add('connected');
                } else {
                    dotElement.classList.remove('connected');
                }
            }
            
            updateDetectionResults(data) {
                const { control_signal, processed_frame, fps } = data;
                
                // 更新角度显示
                document.getElementById('xAngle').textContent = `${control_signal.x_angle.toFixed(1)}°`;
                document.getElementById('yAngle').textContent = `${control_signal.y_angle.toFixed(1)}°`;
                document.getElementById('zAngle').textContent = `${control_signal.z_angle.toFixed(1)}°`;
                
                // 更新动作显示
                document.getElementById('actionValue').textContent = control_signal.action;
                
                // 更新速度显示
                document.getElementById('speedValue').textContent = control_signal.speed;
                
                // 更新抓取状态
                const gripIndicator = document.getElementById('gripIndicator');
                if (control_signal.grip === 1) {
                    gripIndicator.classList.add('active');
                } else {
                    gripIndicator.classList.remove('active');
                }
                
                // 更新FPS显示
                document.getElementById('fpsValue').textContent = fps || 0;
                
                // 更新视频预览
                if (processed_frame) {
                    const videoPreview = document.getElementById('videoPreview');
                    const noVideo = document.getElementById('noVideo');
                    
                    videoPreview.src = processed_frame;
                    videoPreview.style.display = 'block';
                    noVideo.style.display = 'none';
                }
            }
            
            startLocalTest() {
                const button = document.getElementById('testButton');
                const videoSelect = document.getElementById('videoSelect');
                const selectedVideo = videoSelect.value;
                
                if (!selectedVideo) {
                    this.log('❌ 请先选择一个视频文件', 'error');
                    return;
                }
                
                button.disabled = true;
                button.textContent = '启动中...';
                
                // 请求开始本地测试，带上选择的视频
                this.socket.emit('start_local_test', {
                    video_path: selectedVideo
                });
                
                this.log(`正在启动视频测试: ${selectedVideo}`);
                
                setTimeout(() => {
                    button.disabled = false;
                    button.textContent = '开始视频测试';
                }, 5000);
            }
            
            refreshVideoList() {
                this.log('正在刷新视频列表...');
                this.socket.emit('get_video_list');
            }
            
            updateVideoList(videos) {
                const videoSelect = document.getElementById('videoSelect');
                videoSelect.innerHTML = '';
                
                if (videos.length === 0) {
                    const option = document.createElement('option');
                    option.value = '';
                    option.textContent = '未找到视频文件';
                    videoSelect.appendChild(option);
                    
                    this.log('❌ 未找到测试视频文件', 'error');
                    this.log('💡 运行 python create_test_video.py 生成测试视频', 'info');
                } else {
                    // 添加默认选项
                    const defaultOption = document.createElement('option');
                    defaultOption.value = '';
                    defaultOption.textContent = '请选择视频文件';
                    videoSelect.appendChild(defaultOption);
                    
                    // 添加视频文件选项
                    videos.forEach(video => {
                        const option = document.createElement('option');
                        option.value = video.path;
                        option.textContent = `${video.name} (${video.size})`;
                        videoSelect.appendChild(option);
                    });
                    
                    this.log(`✅ 找到 ${videos.length} 个视频文件`);
                }
            }
            
            log(message, type = 'info') {
                const logContainer = document.getElementById('logContainer');
                const timestamp = new Date().toLocaleTimeString();
                const logEntry = document.createElement('div');
                logEntry.className = 'log-entry';
                
                const color = type === 'error' ? '#f00' : '#0f0';
                logEntry.innerHTML = `<span class="log-timestamp">[${timestamp}]</span> <span style="color: ${color}">${message}</span>`;
                
                logContainer.appendChild(logEntry);
                logContainer.scrollTop = logContainer.scrollHeight;
                
                // 限制日志数量
                const entries = logContainer.querySelectorAll('.log-entry');
                if (entries.length > 100) {
                    entries[0].remove();
                }
            }
        }
        
        // 初始化客户端
        document.addEventListener('DOMContentLoaded', () => {
            new HandDetectionClient();
        });
    </script>
</body>
</html>