#!/usr/bin/env python3
# -*- coding: utf-8 -*-

from flask import Flask, jsonify, request
import threading
import time
import cv2
import base64
import numpy as np
from . import config
from .person_detector import PersonDetector
from .distance_calculator import DistanceCalculator
from .map_manager import MapManager
from .mobile_connector import MobileConnector
from .web_orientation_detector import WebOrientationDetector

class WebServer:
    """Web服务器类，管理地图界面和摄像头控制"""
    
    def __init__(self):
        self.app = Flask(__name__)
        self.map_manager = MapManager(
            api_key=config.GAODE_API_KEY,
            camera_lat=config.CAMERA_LATITUDE,
            camera_lng=config.CAMERA_LONGITUDE
        )
        
        # 摄像头相关
        self.camera_active = False
        self.cap = None
        self.detector = None
        self.distance_calculator = None
        self.camera_thread = None
        self.current_frame = None
        self.detection_data = []
        
        # 手机连接相关
        self.mobile_connector = MobileConnector(port=8080)
        self.mobile_frames = {}  # device_id -> latest frame
        self.mobile_mode = False  # 是否启用手机模式
        
        # 🌟 移动端实时数据存储
        self.mobile_locations = {}  # device_id -> latest location
        self.mobile_orientations = {}  # device_id -> latest orientation
        
        # 朝向检测相关
        self.web_orientation_detector = WebOrientationDetector()
        
        # 设置路由
        self.setup_routes()
        
        # 设置手机连接器回调
        self.setup_mobile_callbacks()
        
        # 注册朝向检测API
        self.app.register_blueprint(self.web_orientation_detector.get_blueprint())
        
        # 设置安全头部
        self.setup_security_headers()
    
    def setup_security_headers(self):
        """设置HTTP安全头部"""
        @self.app.after_request
        def add_security_headers(response):
            """为所有响应添加安全头部"""
            response.headers['X-Content-Type-Options'] = 'nosniff'
            response.headers['X-Frame-Options'] = 'SAMEORIGIN'
            response.headers['X-XSS-Protection'] = '1; mode=block'
            response.headers['Referrer-Policy'] = 'strict-origin-when-cross-origin'
            return response
    
    def setup_routes(self):
        """设置Flask路由"""
        
        @self.app.route('/')
        def index():
            """主页面 - 显示地图和控制界面"""
            return self.generate_main_page()
        
        @self.app.route('/mobile/mobile_client.html')
        def mobile_client():
            """手机端客户端页面"""
            return self.serve_mobile_client()
        
        @self.app.route('/mobile/gps_test.html')
        def gps_test():
            """GPS测试页面"""
            return self.serve_gps_test()
        
        @self.app.route('/mobile/permission_guide.html')
        def permission_guide():
            """权限设置指南页面"""
            return self.serve_permission_guide()
        
        @self.app.route('/mobile/baidu_browser_test.html')
        def baidu_browser_test():
            """百度浏览器测试页面"""
            return self.serve_baidu_browser_test()
        
        @self.app.route('/mobile/camera_permission_test.html')
        def camera_permission_test():
            """摄像头权限测试页面"""
            return self.serve_camera_permission_test()
        
        @self.app.route('/mobile/browser_compatibility_guide.html')
        def browser_compatibility_guide():
            """浏览器兼容性指南页面"""
            return self.serve_browser_compatibility_guide()
        
        @self.app.route('/mobile/legacy_browser_help.html')
        def legacy_browser_help():
            """旧版浏览器帮助页面"""
            return self.serve_legacy_browser_help()
        
        @self.app.route('/mobile/harmonyos_camera_fix.html')
        def harmonyos_camera_fix():
            """鸿蒙系统摄像头修复页面"""
            return self.serve_harmonyos_camera_fix()
        
        @self.app.route('/test_device_selector.html')
        def test_device_selector():
            """设备选择器测试页面"""
            try:
                with open('test_device_selector.html', 'r', encoding='utf-8') as f:
                    return f.read()
            except FileNotFoundError:
                return "测试页面未找到", 404
        
        @self.app.route('/api/start_camera', methods=['POST'])
        def start_camera():
            """启动摄像头"""
            try:
                print("🔍 API调用: /api/start_camera")
                if not self.camera_active:
                    print("📷 摄像头当前状态: 离线，正在启动...")
                    self.start_camera_detection()
                    # 等待一下检查启动是否成功
                    time.sleep(0.5)
                    if self.camera_active:
                        print("✅ 摄像头启动成功")
                        return jsonify({"status": "success", "message": "摄像头已启动", "camera_active": True})
                    else:
                        print("❌ 摄像头启动失败")
                        return jsonify({"status": "error", "message": "摄像头启动失败，请检查设备连接"})
                else:
                    print("⚠️ 摄像头已在运行中")
                    return jsonify({"status": "warning", "message": "摄像头已在运行中", "camera_active": True})
            except Exception as e:
                print(f"❌ 摄像头启动异常: {e}")
                import traceback
                traceback.print_exc()
                return jsonify({"status": "error", "message": f"启动失败: {str(e)}"})
        
        @self.app.route('/api/stop_camera', methods=['POST'])
        def stop_camera():
            """停止摄像头"""
            try:
                self.stop_camera_detection()
                return jsonify({"status": "success", "message": "摄像头已停止"})
            except Exception as e:
                return jsonify({"status": "error", "message": f"停止失败: {str(e)}"})
        
        @self.app.route('/api/get_persons_data')
        def get_persons_data():
            """获取人员检测数据"""
            data = self.map_manager.get_persons_data()
            print(f"🌐 API调用 /api/get_persons_data 返回 {len(data)} 个人员数据")
            return jsonify(data)
        
        @self.app.route('/api/get_mobile_devices_data')
        def get_mobile_devices_data():
            """获取移动端设备的实时位置和朝向数据"""
            devices_data = []
            current_time = time.time()
            
            # 获取所有活跃的移动设备数据
            for device_id in set(list(self.mobile_locations.keys()) + list(self.mobile_orientations.keys())):
                device_info = {}
                
                # 获取位置数据
                location_data = self.mobile_locations.get(device_id)
                if location_data and (current_time - location_data['timestamp']) < 30:  # 30秒内的数据有效
                    device_info['location'] = {
                        'latitude': location_data['latitude'],
                        'longitude': location_data['longitude'],
                        'accuracy': location_data['accuracy'],
                        'timestamp': location_data['timestamp']
                    }
                
                # 获取朝向数据
                orientation_data = self.mobile_orientations.get(device_id)
                if orientation_data and (current_time - orientation_data['timestamp']) < 30:  # 30秒内的数据有效
                    device_info['orientation'] = {
                        'heading': orientation_data['heading'],
                        'tilt': orientation_data['tilt'],
                        'roll': orientation_data['roll'],
                        'timestamp': orientation_data['timestamp']
                    }
                
                # 只有有数据的设备才加入返回列表
                if device_info:
                    device_info['device_id'] = device_id
                    devices_data.append(device_info)
            
            return jsonify(devices_data)
        
        @self.app.route('/api/debug_info')
        def debug_info():
            """获取调试信息"""
            debug_data = {
                "camera_active": self.camera_active,
                "persons_count": len(self.map_manager.get_persons_data()),
                "persons_data": self.map_manager.get_persons_data(),
                "detection_count": len(self.detection_data) if self.detection_data else 0,
                "camera_position": {
                    "lat": config.CAMERA_LATITUDE,
                    "lng": config.CAMERA_LONGITUDE,
                    "heading": config.CAMERA_HEADING
                }
            }
            return jsonify(debug_data)
        
        @self.app.route('/api/get_camera_frame')
        def get_camera_frame():
            """获取当前摄像头帧（base64编码）"""
            if self.current_frame is not None:
                _, buffer = cv2.imencode('.jpg', self.current_frame)
                frame_base64 = base64.b64encode(buffer).decode('utf-8')
                return jsonify({
                    "status": "success",
                    "frame": f"data:image/jpeg;base64,{frame_base64}",
                    "active": self.camera_active
                })
            else:
                return jsonify({
                    "status": "no_frame",
                    "frame": None,
                    "active": self.camera_active
                })
        
        # 手机端API路由
        @self.app.route('/mobile/ping', methods=['POST'])
        def mobile_ping():
            """手机端连接测试"""
            try:
                data = request.get_json()
                device_id = data.get('device_id')
                return jsonify({"status": "success", "server_time": time.time(), "device_id": device_id})
            except Exception as e:
                return jsonify({"status": "error", "message": str(e)}), 400
        
        @self.app.route('/mobile/upload', methods=['POST'])
        def mobile_upload():
            """接收手机端数据"""
            try:
                data = request.get_json()
                self.process_mobile_data(data)
                return jsonify({"status": "success", "timestamp": time.time()})
            except Exception as e:
                print(f"⚠️ 处理手机数据错误: {e}")
                return jsonify({"status": "error", "message": str(e)}), 400
        
        @self.app.route('/api/mobile/realtime_data', methods=['POST'])
        def mobile_realtime_data():
            """接收移动端实时GPS和朝向数据"""
            try:
                data = request.get_json() or {}
                device_id = data.get('device_id')
                data_type = data.get('type')
                payload = data.get('data', {})
                
                if not device_id or not data_type:
                    return jsonify({
                        "status": "error", 
                        "message": "设备ID和数据类型不能为空"
                    }), 400
                
                # 处理不同类型的数据
                if data_type == 'location':
                    return self.handle_mobile_location_data(device_id, payload)
                elif data_type == 'orientation':
                    return self.handle_mobile_orientation_data(device_id, payload)
                else:
                    return jsonify({
                        "status": "error", 
                        "message": f"不支持的数据类型: {data_type}"
                    }), 400
                    
            except Exception as e:
                print(f"❌ 移动端实时数据处理错误: {e}")
                return jsonify({
                    "status": "error", 
                    "message": f"数据处理失败: {str(e)}"
                }), 500
        
        @self.app.route('/api/mobile/devices')
        def get_mobile_devices():
            """获取连接的手机设备列表"""
            devices = []
            
            # 首先添加Socket连接的设备
            for device in self.mobile_connector.get_online_devices():
                devices.append({
                    "device_id": device.device_id,
                    "device_name": device.device_name,
                    "battery_level": device.battery_level,
                    "is_online": device.is_online,
                    "last_seen": device.last_seen,
                    "location": device.current_location
                })
            
            # 然后添加HTTP API连接的设备
            current_time = time.time()
            for device_id, frame_data in self.mobile_frames.items():
                # 检查是否已经在Socket设备列表中
                device_exists = any(d["device_id"] == device_id for d in devices)
                if not device_exists:
                    device_info = frame_data.get('device_info', {})
                    last_seen = frame_data.get('timestamp', current_time)
                    
                    # 设备被认为在线如果最后一次见到的时间在30秒内
                    is_online = (current_time - last_seen) < 30
                    
                    location = None
                    gps_data = device_info.get('gps')
                    if gps_data and gps_data.get('latitude') and gps_data.get('longitude'):
                        location = {
                            "lat": gps_data['latitude'], 
                            "lng": gps_data['longitude'], 
                            "accuracy": gps_data.get('accuracy', 0)
                        }
                    
                    devices.append({
                        "device_id": device_id,
                        "device_name": device_info.get('device_name', f'HTTP-Device-{device_id[:8]}'),
                        "battery_level": device_info.get('battery', 100),
                        "is_online": is_online,
                        "last_seen": last_seen,
                        "location": location,
                        "connection_type": "HTTP"
                    })
            
            return jsonify(devices)
        
        @self.app.route('/api/mobile/toggle', methods=['POST'])
        def toggle_mobile_mode():
            """切换手机模式"""
            try:
                if not self.mobile_mode:
                    # 启动手机模式
                    if self.mobile_connector.start_server():
                        self.mobile_mode = True
                        # 停止本地摄像头
                        if self.camera_active:
                            self.stop_camera_detection()
                        return jsonify({"status": "success", "message": "手机模式已启动", "mobile_mode": True})
                    else:
                        return jsonify({"status": "error", "message": "手机服务器启动失败"})
                else:
                    # 停止手机模式
                    self.mobile_connector.stop_server()
                    self.mobile_mode = False
                    self.mobile_frames.clear()
                    self.map_manager.clear_persons()
                    return jsonify({"status": "success", "message": "手机模式已停止", "mobile_mode": False})
            except Exception as e:
                return jsonify({"status": "error", "message": str(e)})

        @self.app.route('/api/connect_remote_device', methods=['POST'])
        def connect_remote_device():
            """连接到远程设备"""
            try:
                data = request.get_json()
                device_id = data.get('device_id')
                client_id = data.get('client_id')
                
                # 检查设备是否存在 - 首先检查Socket连接的设备
                target_device = None
                for device in self.mobile_connector.get_online_devices():
                    if device.device_id == device_id:
                        target_device = device
                        break
                
                # 如果在Socket设备中没找到，检查HTTP连接的设备
                if not target_device and device_id in self.mobile_frames:
                    frame_data = self.mobile_frames[device_id]
                    device_info = frame_data.get('device_info', {})
                    current_time = time.time()
                    last_seen = frame_data.get('timestamp', current_time)
                    
                    # 检查设备是否在线（30秒内有数据）
                    if (current_time - last_seen) < 30:
                        # 创建一个临时设备对象用于响应
                        target_device = {
                            'device_id': device_id,
                            'device_name': device_info.get('device_name', f'HTTP-Device-{device_id[:8]}'),
                            'battery_level': device_info.get('battery', 100),
                            'current_location': None
                        }
                        
                        # 如果有GPS数据，添加位置信息
                        gps_data = device_info.get('gps')
                        if gps_data and gps_data.get('latitude') and gps_data.get('longitude'):
                            target_device['current_location'] = {
                                "lat": gps_data['latitude'], 
                                "lng": gps_data['longitude'], 
                                "accuracy": gps_data.get('accuracy', 0)
                            }
                
                if not target_device:
                    return jsonify({"status": "error", "message": "目标设备未找到或已离线"}), 404
                
                # 建立连接关系
                connection_info = {
                    "client_id": client_id,
                    "device_id": device_id,
                    "connected_at": time.time(),
                    "status": "connected"
                }
                
                # 存储连接信息（这里可以扩展为更复杂的连接管理）
                if not hasattr(self, 'remote_connections'):
                    self.remote_connections = {}
                self.remote_connections[f"{client_id}->{device_id}"] = connection_info
                
                # 处理不同格式的设备数据
                if isinstance(target_device, dict):
                    # HTTP连接的设备（字典格式）
                    device_name = target_device['device_name']
                    device_info = {
                        "device_id": target_device['device_id'],
                        "device_name": target_device['device_name'],
                        "battery_level": target_device['battery_level'],
                        "location": target_device['current_location']
                    }
                else:
                    # Socket连接的设备（对象格式）
                    device_name = target_device.device_name
                    device_info = {
                        "device_id": target_device.device_id,
                        "device_name": target_device.device_name,
                        "battery_level": target_device.battery_level,
                        "location": target_device.current_location
                    }
                
                return jsonify({
                    "status": "success", 
                    "message": f"已连接到设备 {device_name}",
                    "device_info": device_info
                })
                
            except Exception as e:
                return jsonify({"status": "error", "message": str(e)}), 500

        @self.app.route('/api/remote_device/stream/<device_id>')
        def get_remote_device_stream(device_id):
            """获取远程设备的视频流"""
            try:
                # 获取指定设备的最新帧
                if device_id in self.mobile_frames:
                    frame_data = self.mobile_frames[device_id]
                    device_info = frame_data.get('device_info', {})
                    
                    # 准备返回数据，包含GPS信息
                    response_data = {
                        "status": "success",
                        "frame": f"data:image/jpeg;base64,{frame_data.get('frame')}",
                        "timestamp": frame_data.get('timestamp'),
                        "device_info": device_info
                    }
                    
                    # 如果有GPS数据，加入响应中
                    gps_data = device_info.get('gps')
                    if gps_data and gps_data.get('latitude') and gps_data.get('longitude'):
                        response_data['gps'] = {
                            "lat": gps_data['latitude'],
                            "lng": gps_data['longitude'],
                            "accuracy": gps_data.get('accuracy', 0)
                        }
                    
                    return jsonify(response_data)
                else:
                    return jsonify({
                        "status": "no_frame",
                        "message": "设备无视频数据"
                    }), 404
            except Exception as e:
                return jsonify({"status": "error", "message": str(e)}), 500
        
        @self.app.route('/favicon.ico')
        def favicon():
            return '', 204  # 返回空内容，状态码204表示无内容
    
    def draw_info_panel(self, frame, person_count=0):
        """绘制信息面板 - 完全复制main.py的逻辑"""
        height, width = frame.shape[:2]
        
        # 绘制顶部信息栏
        info_height = 60
        cv2.rectangle(frame, (0, 0), (width, info_height), (0, 0, 0), -1)
        
        # 显示FPS（Web版本不需要实时FPS，显示固定文本）
        fps_text = "Web Mode"
        cv2.putText(frame, fps_text, (10, 25), config.FONT, 0.6, (0, 255, 0), 2)
        
        # 显示人员计数
        person_text = f"Persons: {person_count}"
        cv2.putText(frame, person_text, (150, 25), config.FONT, 0.6, (0, 255, 255), 2)
        
        # 显示模型信息
        if hasattr(self, 'person_detector') and self.person_detector:
            model_text = self.person_detector.get_model_info()
        else:
            model_text = "YOLO Model: Loading..."
        cv2.putText(frame, model_text, (10, 45), config.FONT, 0.5, (255, 255, 255), 1)
        
        # 显示时间信息
        time_text = f"Time: {time.strftime('%H:%M:%S')}"
        cv2.putText(frame, time_text, (width - 150, 25), config.FONT, 0.5, (255, 255, 0), 1)
        
        # 显示地图状态
        map_status = "Map: ON"
        cv2.putText(frame, map_status, (10, height - 10), 
                   config.FONT, 0.5, (0, 255, 255), 1)
        
        # 显示摄像头信息
        camera_info = f"Camera: Local ({config.CAMERA_LATITUDE:.4f}, {config.CAMERA_LONGITUDE:.4f})"
        cv2.putText(frame, camera_info, (width - 400, height - 10), 
                   config.FONT, 0.4, (255, 255, 255), 1)
        
        return frame
    
    def draw_backend_info_panel(self, frame, person_count=0, fps=0):
        """绘制后端摄像头的信息面板 - 显示实时FPS"""
        height, width = frame.shape[:2]
        
        # 绘制顶部信息栏
        info_height = 60
        cv2.rectangle(frame, (0, 0), (width, info_height), (0, 0, 0), -1)
        
        # 显示实时FPS
        fps_text = f"FPS: {fps}"
        cv2.putText(frame, fps_text, (10, 25), config.FONT, 0.6, (0, 255, 0), 2)
        
        # 显示人员计数
        person_text = f"Persons: {person_count}"
        cv2.putText(frame, person_text, (150, 25), config.FONT, 0.6, (0, 255, 255), 2)
        
        # 显示模型信息
        if hasattr(self, 'detector') and self.detector:
            model_text = self.detector.get_model_info()
        else:
            model_text = "YOLO Model: Loading..."
        cv2.putText(frame, model_text, (10, 45), config.FONT, 0.5, (255, 255, 255), 1)
        
        # 显示时间信息
        time_text = f"Time: {time.strftime('%H:%M:%S')}"
        cv2.putText(frame, time_text, (width - 150, 25), config.FONT, 0.5, (255, 255, 0), 1)
        
        # 显示地图状态
        map_status = "Map: ON"
        cv2.putText(frame, map_status, (10, height - 10), 
                   config.FONT, 0.5, (0, 255, 255), 1)
        
        # 显示摄像头信息
        camera_info = f"Camera: Backend ({config.CAMERA_LATITUDE:.4f}, {config.CAMERA_LONGITUDE:.4f})"
        cv2.putText(frame, camera_info, (width - 450, height - 10), 
                   config.FONT, 0.4, (255, 255, 255), 1)
        
        # 显示操作提示
        help_text = "Real-time Detection Mode"
        cv2.putText(frame, help_text, (width - 250, 45), 
                   config.FONT, 0.5, (255, 255, 0), 1)
        
        return frame
    
    def setup_mobile_callbacks(self):
        """设置手机连接器回调函数"""
        self.mobile_connector.add_frame_callback(self.on_mobile_frame)
        self.mobile_connector.add_location_callback(self.on_mobile_location)
        self.mobile_connector.add_device_callback(self.on_mobile_device_event)
    
    def process_mobile_data(self, data):
        """处理手机端发送的数据"""
        device_id = data.get('device_id')
        if not device_id:
            raise ValueError("缺少device_id")
        
        # 处理图像数据
        if 'frame' in data:
            try:
                # 存储base64图像数据（用于远程设备流）
                self.mobile_frames[device_id] = {
                    'frame': data['frame'],
                    'timestamp': data.get('timestamp', time.time()),
                    'device_info': {
                        'device_name': data.get('device_name', 'Unknown'),
                        'battery': data.get('battery', 100),
                        'gps': data.get('gps')
                    }
                }
                
                # 解码base64图像用于检测
                frame_data = base64.b64decode(data['frame'])
                frame = cv2.imdecode(np.frombuffer(frame_data, np.uint8), cv2.IMREAD_COLOR)
                
                if frame is not None:
                    
                    # 如果启用了检测器，进行人体检测
                    if not self.detector:
                        self.detector = PersonDetector()
                        self.distance_calculator = DistanceCalculator()
                    
                    # 处理GPS和设备信息
                    gps_data = data.get('gps')
                    if gps_data and gps_data.get('latitude') and gps_data.get('longitude'):
                        self.process_mobile_detection(device_id, frame, gps_data)
                    
                    print(f"📱 收到设备 {device_id[:8]} 的图像数据")
                    
            except Exception as e:
                print(f"⚠️ 处理手机图像数据错误: {e}")
                raise
    
    def process_mobile_detection(self, device_id, frame, gps_data):
        """处理手机图像的人体检测"""
        try:
            # 存储移动设备的最新GPS位置
            if gps_data:
                print(f"📍 设备 {device_id[:8]} GPS位置: ({gps_data['latitude']:.6f}, {gps_data['longitude']:.6f})")
                
                # 更新设备在移动连接器中的位置信息
                if hasattr(self.mobile_connector, 'update_device_location'):
                    self.mobile_connector.update_device_location(device_id, gps_data['latitude'], gps_data['longitude'])
            
            # 创建帧的副本用于绘制检测框
            processed_frame = frame.copy()
            
            # 检测人体
            detections = self.detector.detect_persons(frame)
            
            if len(detections) > 0:
                print(f"📱 设备 {device_id[:8]} 检测到 {len(detections)} 个人")
                
                # 清除地图上该设备的旧标记
                self.map_manager.clear_persons()
                
                for i, detection in enumerate(detections):
                    bbox = detection[:4]  # [x1, y1, x2, y2]
                    x1, y1, x2, y2 = bbox
                    
                    # 绘制检测框
                    cv2.rectangle(processed_frame, (int(x1), int(y1)), (int(x2), int(y2)), (0, 255, 0), 2)
                    
                    # 计算距离（基于手机摄像头）
                    distance = self.distance_calculator.get_distance(bbox)
                    distance_meters = distance / 100.0
                    
                    # 绘制距离标签
                    label = f"Person {i+1}: {distance_meters:.1f}m"
                    label_size = cv2.getTextSize(label, cv2.FONT_HERSHEY_SIMPLEX, 0.6, 2)[0]
                    cv2.rectangle(processed_frame, (int(x1), int(y1-label_size[1]-10)), 
                                (int(x1+label_size[0]), int(y1)), (0, 255, 0), -1)
                    cv2.putText(processed_frame, label, (int(x1), int(y1-5)), 
                              cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 0), 2)
                    
                    # 🎯 使用精确的GPS坐标计算
                    # 获取设备朝向信息
                    device_heading = 0  # 默认朝向正北
                    if device_id in self.mobile_orientations:
                        orientation_data = self.mobile_orientations[device_id]
                        if time.time() - orientation_data['timestamp'] < 30:  # 30秒内的朝向数据有效
                            device_heading = orientation_data['heading']
                    
                    # 使用距离计算器的精确算法计算人员GPS坐标
                    frame_height, frame_width = frame.shape[:2]
                    person_lat, person_lng = self.distance_calculator.calculate_person_gps_position(
                        camera_lat=gps_data['latitude'],
                        camera_lng=gps_data['longitude'],
                        camera_heading=device_heading,
                        bbox=bbox,
                        distance_meters=distance_meters,
                        frame_width=frame_width,
                        frame_height=frame_height,
                        camera_fov=60  # 假设移动设备摄像头视场角为60度
                    )
                    
                    # 🔍 检查人员是否在摄像头视野范围内
                    in_fov = self.distance_calculator.is_person_in_camera_fov(
                        camera_lat=gps_data['latitude'],
                        camera_lng=gps_data['longitude'],
                        camera_heading=device_heading,
                        person_lat=person_lat,
                        person_lng=person_lng,
                        camera_fov=60,
                        max_distance=50  # 最大检测距离50米
                    )
                    
                    if in_fov:
                        # 添加到地图
                        self.map_manager.add_person_at_coordinates(
                            person_lat, person_lng, 
                            f"Mobile-P{i+1}", 
                            distance_meters,
                            device_id
                        )
                        print(f"📍 手机检测人员 {i+1}: 距离{distance_meters:.1f}m, 坐标({person_lat:.6f}, {person_lng:.6f}) ✅视野内")
                    else:
                        print(f"⚠️ 手机检测人员 {i+1}: 距离{distance_meters:.1f}m, 坐标({person_lat:.6f}, {person_lng:.6f}) ❌超出视野")
            else:
                # 即使没有检测到人员，也要清除旧标记，避免误导
                print(f"📱 设备 {device_id[:8]} 未检测到人员")
            
            # 绘制信息面板
            processed_frame = self.draw_backend_info_panel(processed_frame, len(detections), fps=60)
            
            # 在顶部添加移动设备标识
            device_label = f"Mobile Device: {device_id[:8]}"
            cv2.putText(processed_frame, device_label, (10, 80), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (255, 255, 0), 2)
            
            # 更新当前帧供前端显示
            self.current_frame = processed_frame
            
            # 标记摄像头为活跃状态
            self.camera_active = True
                
        except Exception as e:
            print(f"⚠️ 手机检测处理错误: {e}")
    
    def on_mobile_frame(self, device_id, frame, device):
        """手机帧数据回调"""
        # 这个方法会被MobileConnector调用，但我们已经在process_mobile_data中处理了
        pass
    
    def on_mobile_location(self, device_id, location, device):
        """手机位置数据回调"""
        lat, lng, accuracy = location
        print(f"📍 设备 {device_id[:8]} 位置更新: ({lat:.6f}, {lng:.6f})")
    
    def on_mobile_device_event(self, event_type, device):
        """手机设备事件回调"""
        if event_type == 'device_connected':
            print(f"📱 新设备连接: {device.device_name} ({device.device_id[:8]})")
        elif event_type == 'device_disconnected':
            print(f"📱 设备断开: {device.device_name} ({device.device_id[:8]})")
            # 清理该设备的数据
            if device.device_id in self.mobile_frames:
                del self.mobile_frames[device.device_id]
            # 🌟 清理实时数据
            if device.device_id in self.mobile_locations:
                del self.mobile_locations[device.device_id]
            if device.device_id in self.mobile_orientations:
                del self.mobile_orientations[device.device_id]
    
    def handle_mobile_location_data(self, device_id, location_data):
        """处理移动端GPS位置数据"""
        try:
            latitude = location_data.get('latitude')
            longitude = location_data.get('longitude')
            accuracy = location_data.get('accuracy', 100)
            timestamp = location_data.get('timestamp', time.time())
            
            if latitude is None or longitude is None:
                return jsonify({
                    "status": "error",
                    "message": "GPS坐标数据不完整"
                }), 400
            
            # 存储位置数据
            self.mobile_locations[device_id] = {
                'latitude': latitude,
                'longitude': longitude,
                'accuracy': accuracy,
                'timestamp': timestamp
            }
            
            print(f"📍 设备 {device_id[:8]} GPS更新: ({latitude:.6f}, {longitude:.6f}) ±{accuracy}m")
            
            return jsonify({
                "status": "success",
                "message": "GPS位置数据已接收"
            })
            
        except Exception as e:
            print(f"❌ GPS数据处理错误: {e}")
            return jsonify({
                "status": "error",
                "message": f"GPS数据处理失败: {str(e)}"
            }), 500
    
    def handle_mobile_orientation_data(self, device_id, orientation_data):
        """处理移动端设备朝向数据"""
        try:
            heading = orientation_data.get('heading')
            tilt = orientation_data.get('tilt')
            roll = orientation_data.get('roll')
            timestamp = orientation_data.get('timestamp', time.time())
            
            if heading is None:
                return jsonify({
                    "status": "error",
                    "message": "朝向数据不完整"
                }), 400
            
            # 存储朝向数据
            self.mobile_orientations[device_id] = {
                'heading': heading,
                'tilt': tilt,
                'roll': roll,
                'timestamp': timestamp
            }
            
            print(f"🧭 设备 {device_id[:8]} 朝向更新: {heading:.1f}° (倾斜:{tilt:.1f}°)")
            
            return jsonify({
                "status": "success",
                "message": "朝向数据已接收"
            })
            
        except Exception as e:
            print(f"❌ 朝向数据处理错误: {e}")
            return jsonify({
                "status": "error",
                "message": f"朝向数据处理失败: {str(e)}"
            }), 500
    
    def serve_mobile_client(self):
        """提供手机端客户端页面"""
        try:
            with open('mobile/mobile_client.html', 'r', encoding='utf-8') as f:
                return f.read()
        except FileNotFoundError:
            return """
            <html>
            <head><title>文件未找到</title></head>
            <body>
                <h1>❌ 手机端客户端文件未找到</h1>
                <p>请确保 mobile/mobile_client.html 文件存在</p>
                <p>或者直接访问该文件的完整路径</p>
            </body>
            </html>
            """, 404
    
    def serve_gps_test(self):
        """提供GPS测试页面"""
        try:
            with open('mobile/gps_test.html', 'r', encoding='utf-8') as f:
                return f.read()
        except FileNotFoundError:
            return """
            <html>
            <head><title>文件未找到</title></head>
            <body>
                <h1>❌ GPS测试页面未找到</h1>
                <p>请确保 mobile/gps_test.html 文件存在</p>
            </body>
            </html>
            """, 404
    
    def serve_permission_guide(self):
        """提供权限设置指南页面"""
        try:
            with open('mobile/permission_guide.html', 'r', encoding='utf-8') as f:
                return f.read()
        except FileNotFoundError:
            return """
            <html>
            <head><title>文件未找到</title></head>
            <body>
                <h1>❌ 权限指南页面未找到</h1>
                <p>请确保 mobile/permission_guide.html 文件存在</p>
            </body>
            </html>
            """, 404
    
    def serve_baidu_browser_test(self):
        """提供百度浏览器测试页面"""
        try:
            with open('mobile/baidu_browser_test.html', 'r', encoding='utf-8') as f:
                return f.read()
        except FileNotFoundError:
            return """
            <html>
            <head><title>文件未找到</title></head>
            <body>
                <h1>❌ 百度浏览器测试页面未找到</h1>
                <p>请确保 mobile/baidu_browser_test.html 文件存在</p>
                <a href="/mobile/mobile_client.html">返回移动客户端</a>
            </body>
            </html>
            """, 404
    
    def serve_camera_permission_test(self):
        """提供摄像头权限测试页面"""
        try:
            with open('mobile/camera_permission_test.html', 'r', encoding='utf-8') as f:
                return f.read()
        except FileNotFoundError:
            return """
            <html>
            <head><title>文件未找到</title></head>
            <body>
                <h1>❌ 摄像头权限测试页面未找到</h1>
                <p>请确保 mobile/camera_permission_test.html 文件存在</p>
                <a href="/mobile/mobile_client.html">返回移动客户端</a>
            </body>
            </html>
            """, 404
    
    def serve_browser_compatibility_guide(self):
        """提供浏览器兼容性指南页面"""
        try:
            with open('mobile/browser_compatibility_guide.html', 'r', encoding='utf-8') as f:
                return f.read()
        except FileNotFoundError:
            return """
            <html>
            <head><title>文件未找到</title></head>
            <body>
                <h1>❌ 浏览器兼容性指南页面未找到</h1>
                <p>请确保 mobile/browser_compatibility_guide.html 文件存在</p>
                <a href="/mobile/mobile_client.html">返回移动客户端</a>
            </body>
            </html>
            """, 404
    
    def serve_legacy_browser_help(self):
        """提供旧版浏览器帮助页面"""
        try:
            with open('mobile/legacy_browser_help.html', 'r', encoding='utf-8') as f:
                return f.read()
        except FileNotFoundError:
            return """
            <html>
            <head><title>文件未找到</title></head>
            <body>
                <h1>❌ 旧版浏览器帮助页面未找到</h1>
                <p>请确保 mobile/legacy_browser_help.html 文件存在</p>
                <a href="/mobile/mobile_client.html">返回移动客户端</a>
            </body>
            </html>
            """, 404
    
    def serve_harmonyos_camera_fix(self):
        """提供鸿蒙系统摄像头修复页面"""
        try:
            with open('mobile/harmonyos_camera_fix.html', 'r', encoding='utf-8') as f:
                return f.read()
        except FileNotFoundError:
            return """
            <html>
            <head><title>文件未找到</title></head>
            <body>
                <h1>❌ 鸿蒙系统摄像头修复页面未找到</h1>
                <p>请确保 mobile/harmonyos_camera_fix.html 文件存在</p>
                <a href="/mobile/mobile_client.html">返回移动客户端</a>
            </body>
            </html>
            """, 404
    
    def start_camera_detection(self):
        """启动摄像头检测"""
        if self.camera_active:
            print("⚠️ 摄像头已在运行中")
            return
            
        try:
            print("=" * 60)
            print(f"🔍 开始摄像头检测初始化...")
            print(f"🔍 当前时间: {time.strftime('%Y-%m-%d %H:%M:%S')}")
            print(f"🔍 配置的摄像头索引: {config.CAMERA_INDEX}")
            print(f"🔍 当前camera_active状态: {self.camera_active}")
            
            # 检查OpenCV是否正常
            print(f"🔍 OpenCV版本: {cv2.__version__}")
            
            # 检查系统摄像头
            print("🔍 检查系统可用摄像头...")
            available_cameras = []
            for i in range(10):
                test_cap = cv2.VideoCapture(i)
                if test_cap.isOpened():
                    available_cameras.append(i)
                    test_cap.release()
                    print(f"  ✅ 找到摄像头索引: {i}")
                else:
                    test_cap.release()
            
            if not available_cameras:
                raise Exception("系统中没有找到任何可用的摄像头设备")
            
            print(f"🔍 可用摄像头索引: {available_cameras}")
            
            # 初始化摄像头
            print(f"🔍 正在尝试打开摄像头索引: {config.CAMERA_INDEX}")
            self.cap = cv2.VideoCapture(config.CAMERA_INDEX)
            print(f"🔍 VideoCapture对象创建完成: {self.cap}")
            print(f"🔍 cap.isOpened(): {self.cap.isOpened()}")
            
            # 等待摄像头初始化
            time.sleep(1)
            
            if not self.cap.isOpened():
                print(f"❌ 初始摄像头索引 {config.CAMERA_INDEX} 打开失败")
                # 尝试其他摄像头索引
                success = False
                for i in available_cameras:
                    print(f"🔍 尝试备用摄像头索引: {i}")
                    if self.cap:
                        self.cap.release()
                    self.cap = cv2.VideoCapture(i)
                    time.sleep(0.8)  # 增加等待时间
                    print(f"🔍 索引 {i} isOpened(): {self.cap.isOpened()}")
                    if self.cap.isOpened():
                        print(f"✅ 成功打开备用摄像头索引: {i}")
                        success = True
                        break
                    else:
                        print(f"❌ 索引 {i} 打开失败")
                        self.cap.release()
                
                if not success:
                    raise Exception(f"无法打开任何摄像头，尝试了索引: {available_cameras}")
            else:
                print(f"✅ 初始摄像头索引 {config.CAMERA_INDEX} 打开成功")
            
            # 设置摄像头参数
            print(f"📐 设置摄像头参数: {config.FRAME_WIDTH}x{config.FRAME_HEIGHT}@{config.FPS}fps")
            self.cap.set(cv2.CAP_PROP_FRAME_WIDTH, config.FRAME_WIDTH)
            self.cap.set(cv2.CAP_PROP_FRAME_HEIGHT, config.FRAME_HEIGHT)
            self.cap.set(cv2.CAP_PROP_FPS, config.FPS)
            
            # 测试读取一帧
            print("🔍 测试摄像头帧读取...")
            for attempt in range(3):
                ret, test_frame = self.cap.read()
                print(f"🔍 读取尝试 {attempt + 1}: ret={ret}, frame={'有效' if test_frame is not None else '无效'}")
                if ret and test_frame is not None:
                    print(f"✅ 摄像头测试成功，实际分辨率: {test_frame.shape[1]}x{test_frame.shape[0]}")
                    break
                time.sleep(0.5)
            else:
                raise Exception("摄像头无法读取图像帧，连续3次尝试都失败")
            
            # 初始化检测器
            print("🤖 初始化YOLO检测器...")
            try:
                self.detector = PersonDetector()
                print("✅ PersonDetector初始化完成")
                self.distance_calculator = DistanceCalculator()
                print("✅ DistanceCalculator初始化完成")
            except Exception as e:
                print(f"❌ 检测器初始化失败: {e}")
                raise e
            
            # 启动检测线程
            print("🔍 设置camera_active = True")
            self.camera_active = True
            print(f"🔍 当前camera_active状态: {self.camera_active}")
            
            print("🔍 创建摄像头检测线程...")
            self.camera_thread = threading.Thread(target=self.camera_detection_loop, name="CameraDetectionThread")
            self.camera_thread.daemon = True
            
            print("🔍 启动摄像头检测线程...")
            self.camera_thread.start()
            print(f"🔍 线程是否存活: {self.camera_thread.is_alive()}")
            
            # 等待线程启动
            time.sleep(1)
            print(f"🔍 启动后camera_active状态: {self.camera_active}")
            print(f"🔍 线程启动后状态: {self.camera_thread.is_alive()}")
            
            print("🎯 摄像头检测线程启动完成")
            print("=" * 60)
            
        except Exception as e:
            self.camera_active = False
            if hasattr(self, 'cap') and self.cap:
                self.cap.release()
            print(f"❌ 摄像头启动失败: {e}")
            raise e
    
    def stop_camera_detection(self):
        """停止摄像头检测"""
        self.camera_active = False
        if self.camera_thread:
            self.camera_thread.join(timeout=2)
        if self.cap:
            self.cap.release()
        self.current_frame = None
        self.detection_data = []
        self.map_manager.clear_persons()
        print("📷 摄像头检测已停止")
    
    def camera_detection_loop(self):
        """摄像头检测循环"""
        fps_counter = 0
        fps_time = time.time()
        current_fps = 0
        frame_count = 0
        
        print("=" * 50)
        print("🔍 摄像头检测循环已启动")
        print(f"🔍 线程名称: {threading.current_thread().name}")
        print(f"🔍 启动时camera_active: {self.camera_active}")
        print(f"🔍 启动时cap对象: {self.cap}")
        print(f"🔍 启动时cap.isOpened(): {self.cap.isOpened() if self.cap else 'cap为None'}")
        print("=" * 50)
        
        while self.camera_active and self.cap:
            try:
                # 详细的读帧调试
                if frame_count % 100 == 0:  # 每100帧输出一次详细状态
                    print(f"🔍 循环状态检查 - 帧{frame_count}: camera_active={self.camera_active}, cap={self.cap is not None}")
                
                ret, frame = self.cap.read()
                if not ret or frame is None:
                    print(f"❌ 无法读取摄像头画面 - 帧{frame_count}: ret={ret}, frame={'有效' if frame is not None else '无效'}")
                    print(f"🔍 当前cap状态: {self.cap}")
                    print(f"🔍 cap.isOpened(): {self.cap.isOpened() if self.cap else 'cap为None'}")
                    break
                
                frame_count += 1
                
                # 检测人体
                try:
                    detections = self.detector.detect_persons(frame)
                except Exception as detect_error:
                    print(f"❌ 人体检测错误 - 帧{frame_count}: {detect_error}")
                    detections = []
                
                # 添加调试输出 (每30帧输出一次状态，避免刷屏)
                if frame_count % 30 == 0 or len(detections) > 0:
                    print(f"📹 帧 {frame_count}: 检测到 {len(detections)} 个人 (FPS: {current_fps})")
                    if len(detections) > 0:
                        print(f"🎯 检测详情: {[f'person_{i}_{det[4]:.2f}' for i, det in enumerate(detections)]}")
                
                # 计算距离并更新地图位置
                self.map_manager.clear_persons()
                distances = []
                
                for i, detection in enumerate(detections):
                    bbox = detection[:4]  # [x1, y1, x2, y2]
                    x1, y1, x2, y2 = bbox
                    distance = self.distance_calculator.get_distance(bbox)
                    distance_str = self.distance_calculator.format_distance(distance)
                    distances.append(distance_str)
                    
                    # 计算人体中心点
                    center_x = (x1 + x2) / 2
                    center_y = (y1 + y2) / 2
                    
                    # 将距离从厘米转换为米
                    distance_meters = distance / 100.0
                    
                    # 🎯 使用精确的GPS坐标计算 - 固定摄像头
                    frame_height, frame_width = frame.shape[:2]
                    lat, lng = self.distance_calculator.calculate_person_gps_position(
                        camera_lat=config.CAMERA_LATITUDE,
                        camera_lng=config.CAMERA_LONGITUDE,
                        camera_heading=config.CAMERA_HEADING,
                        bbox=bbox,
                        distance_meters=distance_meters,
                        frame_width=frame_width,
                        frame_height=frame_height,
                        camera_fov=config.CAMERA_FOV
                    )
                    
                    # 🔍 检查人员是否在摄像头视野范围内
                    in_fov = self.distance_calculator.is_person_in_camera_fov(
                        camera_lat=config.CAMERA_LATITUDE,
                        camera_lng=config.CAMERA_LONGITUDE,
                        camera_heading=config.CAMERA_HEADING,
                        person_lat=lat,
                        person_lng=lng,
                        camera_fov=config.CAMERA_FOV,
                        max_distance=100  # 最大检测距离100米
                    )
                    
                    if in_fov:
                        # 添加到地图
                        self.map_manager.add_person_at_coordinates(
                            lat, lng, f"P{i+1}", distance_meters, "fixed_camera"
                        )
                    
                    if len(detections) > 0:  # 只在有检测时输出详细信息
                        if in_fov:
                            print(f"📍 人员 {i+1}: 像素位置({center_x:.1f}, {center_y:.1f}), 距离{distance_meters:.1f}m, 坐标({lat:.6f}, {lng:.6f}) ✅视野内")
                        else:
                            print(f"⚠️ 人员 {i+1}: 像素位置({center_x:.1f}, {center_y:.1f}), 距离{distance_meters:.1f}m, 坐标({lat:.6f}, {lng:.6f}) ❌超出视野")
                
                # 绘制检测结果（完整的检测框、距离、置信度）
                frame = self.detector.draw_detections(frame, detections, distances)
                
                # 计算FPS
                fps_counter += 1
                current_time = time.time()
                if current_time - fps_time >= 1.0:
                    current_fps = fps_counter
                    fps_counter = 0
                    fps_time = current_time
                
                # 添加完整的信息面板 - 带FPS信息
                frame = self.draw_backend_info_panel(frame, len(detections), current_fps)
                
                # 保存当前帧
                try:
                    self.current_frame = frame.copy()
                    self.detection_data = detections
                    
                    # 每100帧验证一次帧保存
                    if frame_count % 100 == 0:
                        print(f"🔍 帧保存状态 - 帧{frame_count}: current_frame={'已保存' if self.current_frame is not None else '保存失败'}")
                
                except Exception as save_error:
                    print(f"❌ 帧保存错误 - 帧{frame_count}: {save_error}")
                
                # 控制帧率
                time.sleep(1/30)  # 30 FPS
                
            except Exception as e:
                print(f"❌ 检测循环错误 - 帧{frame_count}: {e}")
                import traceback
                traceback.print_exc()
                break
        
        print(f"🛑 摄像头检测循环已结束 - 总处理帧数: {frame_count}")
        print(f"🔍 结束时camera_active: {self.camera_active}")
        print(f"🔍 结束时cap状态: {self.cap}")
        print("=" * 50)
    
    def generate_main_page(self):
        """生成主页面HTML"""
        html_template = f"""<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="utf-8">
    <title>🚁 无人机战场态势感知系统</title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script type="text/javascript" src="https://webapi.amap.com/maps?v=1.4.15&key={config.GAODE_API_KEY}"></script>
    <style>
        body {{ margin: 0; padding: 0; font-family: Arial, sans-serif; background: #1a1a1a; color: white; }}
        #mapContainer {{ width: 100%; height: 100vh; position: relative; }}
        
        .control-panel {{
            position: absolute; top: 20px; left: 20px;
            background: rgba(0, 20, 40, 0.9); border: 2px solid #00aaff; border-radius: 10px;
            padding: 20px; min-width: 300px; 
            -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px);
            box-shadow: 0 0 20px rgba(0, 170, 255, 0.3);
        }}
        
        .control-panel h2 {{ margin: 0 0 15px 0; color: #00aaff; text-align: center; font-size: 18px; }}
        .status-info {{ margin-bottom: 15px; font-size: 14px; }}
        .status-item {{ display: flex; justify-content: space-between; margin: 8px 0; padding: 5px;
            background: rgba(255, 255, 255, 0.1); border-radius: 5px; }}
        .status-value {{ font-weight: bold; }}
        
        .control-buttons {{ display: flex; -ms-flex-direction: column; flex-direction: column; gap: 10px; }}
        .btn {{ padding: 12px 20px; border: none; border-radius: 6px; font-size: 14px;
            font-weight: bold; cursor: pointer; transition: all 0.3s ease; }}
        
        .btn-primary {{ background: linear-gradient(45deg, #00aa00, #00ff00); color: white; }}
        .btn-primary:hover {{ background: linear-gradient(45deg, #00ff00, #00aa00);
            box-shadow: 0 0 15px rgba(0, 255, 0, 0.5); }}
        
        .btn-danger {{ background: linear-gradient(45deg, #aa0000, #ff0000); color: white; }}
        .btn-danger:hover {{ background: linear-gradient(45deg, #ff0000, #aa0000);
            box-shadow: 0 0 15px rgba(255, 0, 0, 0.5); }}
        
        .btn-success {{ background: linear-gradient(45deg, #00aa00, #00ff00); color: white; }}
        .btn-success:hover {{ background: linear-gradient(45deg, #00ff00, #00aa00);
            box-shadow: 0 0 15px rgba(0, 255, 0, 0.5); }}
        
        .btn:disabled {{ background: #666; cursor: not-allowed; opacity: 0.6; }}
        
        .camera-window {{
            position: absolute; top: 20px; right: 20px; width: 320px; height: 280px;
            background: rgba(0, 0, 0, 0.9); border: 2px solid #00aaff; border-radius: 10px;
            overflow: hidden; display: none; 
            -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px);
        }}
        
        .camera-header {{ background: linear-gradient(45deg, #003366, #0066aa);
            padding: 8px 15px; font-size: 14px; font-weight: bold; }}
        
        .camera-content {{ width: 100%; height: calc(100% - 40px); display: flex;
            align-items: center; justify-content: center; position: relative; }}
        
        .camera-image {{ width: 100%; height: 100%; max-width: 100%; max-height: 100%; object-fit: contain; }}
        .camera-placeholder {{ color: #666; text-align: center; font-size: 14px; }}
        
        /* 🌟 无人机脉冲动画效果 */
        @keyframes pulse {{
            0% {{ transform: scale(1); box-shadow: 0 0 15px rgba(255, 152, 0, 0.8); }}
            50% {{ transform: scale(1.1); box-shadow: 0 0 25px rgba(255, 152, 0, 1); }}
            100% {{ transform: scale(1); box-shadow: 0 0 15px rgba(255, 152, 0, 0.8); }}
        }}
        
        .legend {{ position: absolute; bottom: 20px; left: 20px; background: rgba(0, 0, 0, 0.8);
            padding: 15px; border-radius: 8px; font-size: 12px; }}
        
        .legend-item {{ margin: 5px 0; display: flex; align-items: center; }}
        .legend-color {{ width: 16px; height: 16px; border-radius: 50%; margin-right: 8px; }}
        .camera-marker {{ background: #0066ff; }}
        .person-marker {{ background: #ff4444; }}
        .mobile-camera-marker {{ background: #2196F3; }}
        .orientation-arrow {{ background: #FF9800; }}
        
        .alert {{ position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);
            background: rgba(0, 0, 0, 0.9); color: white; padding: 20px; border-radius: 10px;
            border: 2px solid #00aaff; display: none; z-index: 2000; }}
        
        /* 设备选择器样式 */
        .device-selector {{
            position: fixed; top: 0; left: 0; width: 100%; height: 100%;
            background: rgba(0, 0, 0, 0.8); z-index: 3000; display: none;
            align-items: center; justify-content: center;
        }}
        .device-selector-content {{
            background: rgba(0, 20, 40, 0.95); border: 2px solid #00aaff;
            border-radius: 15px; padding: 20px; max-width: 90%; max-height: 80%;
            overflow-y: auto; -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px); min-width: 400px;
        }}
        .device-selector h3 {{ margin: 0 0 15px 0; color: #00aaff; text-align: center; }}
        .device-list {{ margin: 15px 0; }}
        .device-item {{
            background: rgba(255, 255, 255, 0.1); border-radius: 8px; padding: 15px;
            margin: 10px 0; cursor: pointer; transition: all 0.3s ease;
            border: 2px solid transparent;
        }}
        .device-item:hover {{ background: rgba(255, 255, 255, 0.2); border-color: #00aaff; }}
        .device-item.selected {{ background: rgba(0, 170, 255, 0.3); border-color: #00aaff; }}
        .device-item.virtual-device {{
            border-left: 4px solid #ff9800;
            background: linear-gradient(135deg, rgba(255, 152, 0, 0.1), rgba(255, 235, 179, 0.1));
        }}
        .device-item.virtual-device .device-kind {{
            background: #ff9800;
            color: white;
        }}
        .device-name {{ font-weight: bold; color: #00aaff; margin-bottom: 5px; }}
        .device-id {{ font-size: 12px; color: #ccc; font-family: monospace; }}
        .device-kind {{
            display: inline-block; background: #4CAF50; color: white;
            padding: 2px 6px; border-radius: 3px; font-size: 10px; margin-top: 5px;
        }}
        .device-selector-buttons {{ display: flex; justify-content: space-between; margin-top: 20px; }}
        .loading {{ text-align: center; color: #ccc; padding: 20px; }}
        
        /* 朝向检测样式 */
        .orientation-panel {{
            background: rgba(255, 255, 255, 0.95);
            border-radius: 15px;
            padding: 20px;
            margin: 15px;
            box-shadow: 0 8px 25px rgba(0,0,0,0.2);
            -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px);
            border: 1px solid rgba(255, 255, 255, 0.3);
        }}
        
        .orientation-status {{
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 15px;
        }}
        
        .orientation-button {{
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            color: white;
            border: none;
            padding: 12px 20px;
            border-radius: 8px;
            cursor: pointer;
            font-size: 14px;
            font-weight: bold;
            transition: all 0.3s ease;
            margin: 5px;
        }}
        
        .orientation-button:hover {{
            transform: translateY(-2px);
            box-shadow: 0 5px 15px rgba(0,0,0,0.3);
        }}
        
        .orientation-button:disabled {{
            background: #ccc;
            cursor: not-allowed;
            transform: none;
        }}
        
        .gps-status, .heading-status {{
            padding: 8px 12px;
            border-radius: 6px;
            font-size: 12px;
            margin: 5px 0;
        }}
        
        .status-success {{
            background: #d4edda;
            color: #155724;
            border: 1px solid #c3e6cb;
        }}
        
        .status-error {{
            background: #f8d7da;
            color: #721c24;
            border: 1px solid #f5c6cb;
        }}
        
        .status-pending {{
            background: #fff3cd;
            color: #856404;
            border: 1px solid #ffeaa7;
        }}
    </style>
</head>
<body>
    <div id="mapContainer"></div>
    
    <div class="control-panel">
        <h2>🚁 系统控制台</h2>
        <div class="status-info">
            <div class="status-item">
                <span>📍 摄像头位置:</span>
                <span class="status-value">{config.CAMERA_LATITUDE:.4f}, {config.CAMERA_LONGITUDE:.4f}</span>
            </div>
            <div class="status-item">
                <span>🧭 朝向角度:</span>
                <span class="status-value" id="currentHeading">{config.CAMERA_HEADING}°</span>
            </div>
            <div class="status-item">
                <span>📷 摄像头状态:</span>
                <span class="status-value" id="cameraStatus">离线</span>
            </div>
            <div class="status-item">
                <span>👥 检测人数:</span>
                <span class="status-value" id="personCount">0</span>
            </div>
        </div>
        
        <!-- 精简的主要控制区 -->
        <div class="control-buttons">
            <button class="btn btn-primary" id="deviceSelectBtn" onclick="showDeviceSelector()">📷 选择设备</button>
            <button class="btn btn-success" id="startBtn" onclick="startCamera()">🎬 开始侦察</button>
            <button class="btn btn-danger" id="stopBtn" onclick="stopCamera()" disabled>⏹️ 停止</button>
            
            <!-- 高级功能按钮组 -->
            <div style="display: flex; gap: 5px; margin-top: 10px;">
                <button class="btn" onclick="toggleAdvancedPanel()" id="advancedBtn" style="background: #6c757d; color: white; flex: 1; font-size: 12px;">⚙️ 高级</button>
                <button class="btn" onclick="systemDiagnosis()" style="background: #ff9800; color: white; flex: 1; font-size: 12px;">🔧 诊断</button>
            </div>
        </div>
        
        <!-- 可折叠的高级配置面板 -->
        <div id="advancedPanel" style="display: none; margin: 10px 0; padding: 10px; background: rgba(255, 255, 255, 0.1); border-radius: 8px; border: 1px solid rgba(255, 255, 255, 0.2);">
            <div style="font-size: 14px; color: #00aaff; margin-bottom: 8px; text-align: center;">🧭 自动配置</div>
            
            <div style="display: flex; gap: 5px; margin-bottom: 8px;">
                <button onclick="requestGPSPermission()" id="gpsBtn" style="flex: 1; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; border: none; padding: 6px; border-radius: 4px; cursor: pointer; font-size: 11px;">📍 GPS</button>
                <button onclick="requestOrientationPermission()" id="orientationBtn" style="flex: 1; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; border: none; padding: 6px; border-radius: 4px; cursor: pointer; font-size: 11px;">🧭 朝向</button>
            </div>
            
            <div style="display: flex; gap: 5px;">
                <button onclick="autoConfigureCamera()" id="autoConfigBtn" disabled style="flex: 1; background: #666; color: white; border: none; padding: 6px; border-radius: 4px; cursor: not-allowed; font-size: 11px;">🤖 自动</button>
                <button onclick="checkMobileDevices()" style="flex: 1; background: #9C27B0; color: white; border: none; padding: 6px; border-radius: 4px; cursor: pointer; font-size: 11px;">📱 移动端</button>
            </div>
            
            <div style="display: flex; gap: 3px; margin-top: 5px;">
                <div id="gpsStatus" style="flex: 1; font-size: 9px; color: #fff3cd; background: rgba(255, 193, 7, 0.3); padding: 2px 4px; border-radius: 2px; text-align: center;">GPS: 未获取</div>
                <div id="headingStatus" style="flex: 1; font-size: 9px; color: #fff3cd; background: rgba(255, 193, 7, 0.3); padding: 2px 4px; border-radius: 2px; text-align: center;">朝向: 未获取</div>
            </div>
        </div>
        
        <!-- 视野调整按钮 -->
        <button onclick="openSectorControlPanel()" style="
            width: 100%; 
            padding: 12px; 
            background: linear-gradient(135deg, #FF9800, #F57C00); 
            color: white; 
            border: none; 
            border-radius: 8px; 
            cursor: pointer; 
            font-size: 14px; 
            margin: 10px 0;
            box-shadow: 0 3px 10px rgba(255, 152, 0, 0.3);
            transition: all 0.3s ease;
            font-weight: bold;
        " onmouseover="this.style.transform='scale(1.02)'" onmouseout="this.style.transform='scale(1)'">
            🔶 调节无人机视野
        </button>
    </div>
    
    <div class="camera-window" id="cameraWindow">
        <div class="camera-header">📹 实时视频监控</div>
        <div class="camera-content">
            <img class="camera-image" id="cameraImage" alt="实时摄像头画面" style="display: none;">
            <div class="camera-placeholder" id="cameraPlaceholder">等待视频流...</div>
        </div>
    </div>
    
    <div class="legend">
        <div class="legend-item">
            <span style="margin-right: 8px;">💻</span><span>固定指挥中心</span>
        </div>
        <div class="legend-item">
            <span style="margin-right: 8px;">🚁</span><span>移动无人机</span>
        </div>
        <div class="legend-item">
            <span style="margin-right: 8px;">🔶</span><span>无人机视野</span>
        </div>
        <div class="legend-item">
            <span style="margin-right: 8px;">🧑‍🌾</span><span>检测目标</span>
        </div>
    </div>
    
    <div class="alert" id="alertBox"><div id="alertMessage"></div></div>
    
    <!-- 设备选择弹窗 -->
    <div class="device-selector" id="deviceSelector">
        <div class="device-selector-content">
            <h3>📷 选择视频设备</h3>
            
            <!-- 本地设备列表 -->
            <div>
                <h4 style="color: #4CAF50; margin: 15px 0 10px 0;">📱 本地设备</h4>
                <div class="device-list" id="localDeviceList">
                    <div class="loading">正在扫描本地设备...</div>
                </div>
            </div>

            <!-- 远程设备列表 -->
            <div style="background: rgba(255, 255, 255, 0.05); border-radius: 8px; padding: 10px; margin-top: 15px;">
                <h4 style="color: #ff9800; margin: 0 0 10px 0; font-size: 14px;">🌐 远程设备</h4>
                <div class="device-list" id="remoteDeviceList">
                    <div style="color: #ccc; font-size: 12px;">暂无远程设备连接</div>
                </div>
            </div>

            <div class="device-selector-buttons">
                <button class="btn btn-danger" onclick="cancelDeviceSelection()">❌ 取消</button>
                <button class="btn btn-primary" onclick="refreshDevices()">🔄 刷新设备</button>
                <button class="btn btn-success" onclick="useSelectedDevice()" id="useDeviceBtn" disabled>✅ 使用选择的设备</button>
            </div>
        </div>
    </div>

    <!-- 视野调整弹窗 -->
    <div class="device-selector" id="sectorControlPanel" style="display: none;">
        <div class="device-selector-content" style="max-width: 400px;">
            <h3 style="color: #FF9800; margin-bottom: 20px;">🔶 无人机视野调整</h3>
            
            <!-- 实时预览 -->
            <div style="background: rgba(255, 152, 0, 0.1); border-radius: 8px; padding: 15px; margin-bottom: 20px; border: 1px solid rgba(255, 152, 0, 0.3);">
                <div style="text-align: center; margin-bottom: 10px;">
                    <span style="color: #FF9800; font-weight: bold;">📊 当前参数</span>
                </div>
                <div style="display: flex; justify-content: space-between; margin-bottom: 5px;">
                    <span style="color: #ddd;">📏 视野大小:</span>
                    <span id="sectorSizeDisplay" style="color: #FF9800; font-weight: bold;">50px</span>
                </div>
                <div style="display: flex; justify-content: space-between;">
                    <span style="color: #ddd;">📐 视野角度:</span>
                    <span id="sectorAngleDisplay" style="color: #FF9800; font-weight: bold;">90°</span>
                </div>
            </div>
            
            <!-- 扇形大小控制 -->
            <div style="margin-bottom: 20px;">
                <div style="color: #ddd; margin-bottom: 10px; font-size: 14px;">📏 调整视野大小</div>
                <div style="display: flex; gap: 8px;">
                    <button onclick="adjustSectorSize(-10)" style="flex: 1; background: #FF5722; color: white; border: none; padding: 10px; border-radius: 6px; cursor: pointer; font-size: 12px; transition: all 0.2s;">🔽 缩小</button>
                    <button onclick="adjustSectorSize(10)" style="flex: 1; background: #4CAF50; color: white; border: none; padding: 10px; border-radius: 6px; cursor: pointer; font-size: 12px; transition: all 0.2s;">🔼 放大</button>
                </div>
            </div>
            
            <!-- 扇形角度控制 -->
            <div style="margin-bottom: 20px;">
                <div style="color: #ddd; margin-bottom: 10px; font-size: 14px;">📐 调整视野角度</div>
                <div style="display: flex; gap: 8px;">
                    <button onclick="adjustSectorAngle(-15)" style="flex: 1; background: #FF5722; color: white; border: none; padding: 10px; border-radius: 6px; cursor: pointer; font-size: 12px; transition: all 0.2s;">◀️ 收窄</button>
                    <button onclick="adjustSectorAngle(15)" style="flex: 1; background: #4CAF50; color: white; border: none; padding: 10px; border-radius: 6px; cursor: pointer; font-size: 12px; transition: all 0.2s;">▶️ 扩大</button>
                </div>
            </div>
            
            <!-- 快速预设 -->
            <div style="margin-bottom: 25px;">
                <div style="color: #ddd; margin-bottom: 10px; font-size: 14px;">⚡ 快速预设</div>
                <div style="display: flex; gap: 6px;">
                    <button onclick="setSectorPreset(40, 60)" style="flex: 1; background: #2196F3; color: white; border: none; padding: 8px; border-radius: 6px; cursor: pointer; font-size: 11px; transition: all 0.2s;">🎯 精确<br><small>40px 60°</small></button>
                    <button onclick="setSectorPreset(50, 90)" style="flex: 1; background: #FF9800; color: white; border: none; padding: 8px; border-radius: 6px; cursor: pointer; font-size: 11px; transition: all 0.2s;">📷 标准<br><small>50px 90°</small></button>
                    <button onclick="setSectorPreset(70, 120)" style="flex: 1; background: #9C27B0; color: white; border: none; padding: 8px; border-radius: 6px; cursor: pointer; font-size: 11px; transition: all 0.2s;">🌐 广角<br><small>70px 120°</small></button>
                </div>
            </div>
            
            <!-- 关闭按钮 -->
            <div style="text-align: center;">
                <button onclick="closeSectorControlPanel()" style="
                    background: #666; 
                    color: white; 
                    border: none; 
                    padding: 12px 24px; 
                    border-radius: 6px; 
                    cursor: pointer; 
                    font-size: 14px;
                    transition: all 0.2s;
                ">✅ 完成调整</button>
            </div>
            
            <div style="font-size: 11px; color: #999; margin-top: 15px; text-align: center;">
                💡 修改会实时应用到所有无人机视野
            </div>
        </div>
    </div>

    <script>
        var map = new AMap.Map('mapContainer', {{
            zoom: 19, center: [{config.CAMERA_LONGITUDE}, {config.CAMERA_LATITUDE}],
            mapStyle: 'amap://styles/dark'
        }});

        // 添加地图控件
        // map.addControl(new AMap.Scale());  // 临时注释掉以避免API兼容性问题
        // map.addControl(new AMap.ToolBar());
        
        var cameraMarker = new AMap.Marker({{
            position: [{config.CAMERA_LONGITUDE}, {config.CAMERA_LATITUDE}],
            content: `<div style="
                font-size: 24px; 
                display: flex; 
                align-items: center; 
                justify-content: center;
                width: 32px;
                height: 32px;
                background: rgba(0, 150, 255, 0.9);
                border-radius: 50%;
                border: 2px solid #0080ff;
                box-shadow: 0 0 10px rgba(0, 150, 255, 0.6);
            ">💻</div>`,
            offset: new AMap.Pixel(-16, -16),
            title: '固定摄像头 - 指挥中心'
        }});
        map.add(cameraMarker);
        
        // 🎯 为固定摄像头创建视野扇形 (蓝色表示固定设备)
        var fixedCameraFOV = createGeographicSector(
            {config.CAMERA_LONGITUDE}, 
            {config.CAMERA_LATITUDE}, 
            {config.CAMERA_HEADING}, 
            {config.CAMERA_FOV}, 
            100,  // 100米检测范围
            '#2196F3'  // 蓝色，与固定摄像头标记颜色匹配
        );
        map.add(fixedCameraFOV);
        
        // 为摄像头标记添加点击事件
        var cameraInfoWindow = new AMap.InfoWindow({{
            isCustom: true,
            content: createCameraInfoContent(),
            offset: new AMap.Pixel(0, -30)
        }});
        
        cameraMarker.on('click', function() {{
            cameraInfoWindow.open(map, cameraMarker.getPosition());
        }});
        
        // 创建摄像头信息内容
        function createCameraInfoContent() {{
            return `
                <div style="background: linear-gradient(135deg, #1e3c72, #2a5298); color: white; padding: 15px; border-radius: 10px; box-shadow: 0 4px 15px rgba(0,0,0,0.3); font-family: Arial, sans-serif; min-width: 250px;">
                    <div style="display: flex; align-items: center; margin-bottom: 10px;">
                        <div style="width: 32px; height: 32px; background: #00ff00; border-radius: 50%; display: flex; align-items: center; justify-content: center; margin-right: 10px;">
                            📷
                        </div>
                        <h3 style="margin: 0; color: #00ff00;">🚁 侦察摄像头</h3>
                    </div>
                    <div style="border-top: 1px solid rgba(255,255,255,0.3); padding-top: 10px;">
                        <p style="margin: 5px 0;"><strong>📍 位置:</strong> {config.CAMERA_LATITUDE:.6f}, {config.CAMERA_LONGITUDE:.6f}</p>
                        <p style="margin: 5px 0;"><strong>🧭 朝向:</strong> {config.CAMERA_HEADING}° (正北为0°)</p>
                        <p style="margin: 5px 0;"><strong>👁️ 视场角:</strong> {config.CAMERA_FOV}°</p>
                        <p style="margin: 5px 0;"><strong>📺 分辨率:</strong> {config.FRAME_WIDTH}x{config.FRAME_HEIGHT}</p>
                        <p style="margin: 5px 0;"><strong>⚡ 状态:</strong> <span id="cameraInfoStatus" style="color: #00ff00;">在线</span></p>
                    </div>
                    <div style="text-align: center; margin-top: 10px; font-size: 12px; color: #cccccc;">
                        点击其他区域关闭信息窗口
                    </div>
                </div>
            `;
        }}
        
        // 创建人员信息内容
        function createPersonInfoContent(person) {{
            var detectionTime = new Date(person.timestamp * 1000);
            var timeStr = detectionTime.toLocaleTimeString('zh-CN');
            
            // 计算距离摄像头的方向
            var bearing = calculateBearing({config.CAMERA_LATITUDE}, {config.CAMERA_LONGITUDE}, person.lat, person.lng);
            var direction = getDirectionName(bearing);
            
            return `
                <div style="background: linear-gradient(135deg, #8B0000, #DC143C); color: white; padding: 15px; border-radius: 10px; box-shadow: 0 4px 15px rgba(0,0,0,0.3); font-family: Arial, sans-serif; min-width: 280px;">
                    <div style="display: flex; align-items: center; margin-bottom: 10px;">
                        <div style="width: 32px; height: 32px; background: #ff4444; border-radius: 50%; display: flex; align-items: center; justify-content: center; margin-right: 10px;">
                            👤
                        </div>
                        <h3 style="margin: 0; color: #ffcccc;">🎯 检测目标</h3>
                    </div>
                    <div style="border-top: 1px solid rgba(255,255,255,0.3); padding-top: 10px;">
                        <p style="margin: 5px 0;"><strong>🆔 标识:</strong> ${{person.id}}</p>
                        <p style="margin: 5px 0;"><strong>📍 坐标:</strong> ${{person.lat.toFixed(6)}}, ${{person.lng.toFixed(6)}}</p>
                        <p style="margin: 5px 0;"><strong>📏 距离:</strong> ${{person.distance.toFixed(1)}}米</p>
                        <p style="margin: 5px 0;"><strong>🧭 方向:</strong> ${{direction}} (${{bearing.toFixed(0)}}°)</p>
                        <p style="margin: 5px 0;"><strong>📺 像素位置:</strong> (${{Math.round(person.pixel_x)}}, ${{Math.round(person.pixel_y)}})</p>
                        <p style="margin: 5px 0;"><strong>⏰ 检测时间:</strong> ${{timeStr}}</p>
                    </div>
                    <div style="text-align: center; margin-top: 10px; padding-top: 10px; border-top: 1px solid rgba(255,255,255,0.3);">
                        <div style="color: #ffcccc; font-size: 12px;">🔴 实时跟踪目标</div>
                        <div style="color: #cccccc; font-size: 11px; margin-top: 5px;">点击其他区域关闭信息窗口</div>
                    </div>
                </div>
            `;
        }}
        
        // 计算两点间的方位角
        function calculateBearing(lat1, lng1, lat2, lng2) {{
            var dLng = (lng2 - lng1) * Math.PI / 180;
            var lat1Rad = lat1 * Math.PI / 180;
            var lat2Rad = lat2 * Math.PI / 180;
            
            var y = Math.sin(dLng) * Math.cos(lat2Rad);
            var x = Math.cos(lat1Rad) * Math.sin(lat2Rad) - Math.sin(lat1Rad) * Math.cos(lat2Rad) * Math.cos(dLng);
            
            var bearing = Math.atan2(y, x) * 180 / Math.PI;
            return (bearing + 360) % 360; // 确保结果在0-360度之间
        }}
        
        // 将角度转换为方向名称
        function getDirectionName(bearing) {{
            var directions = [
                '正北', '北偏东', '东北', '东偏北',
                '正东', '东偏南', '东南', '南偏东',
                '正南', '南偏西', '西南', '西偏南',
                '正西', '西偏北', '西北', '北偏西'
            ];
            var index = Math.round(bearing / 22.5) % 16;
            return directions[index];
        }}
        
        // 确保personMarkers数组正确初始化
        var personMarkers = [];
        // 🌟 移动设备标记数组
        var mobileDeviceMarkers = {{}};
        // 🌟 当前移动设备数据缓存
        var currentMobileDevicesData = [];
        
        async function startCamera() {{
            try {{
                // 🚀 修复：如果没有选择设备，自动使用本地摄像头
                if (!selectedDeviceId || !selectedDeviceInfo) {{
                    console.log('⚠️ 未选择设备，自动使用本地摄像头');
                    selectedDeviceId = 'local_camera_default';
                    selectedDeviceInfo = {{
                        isRemote: false,
                        name: '本地摄像头 (默认)',
                        device_id: 'local_camera_default'
                    }};
                    showAlert('自动选择本地摄像头设备', 'info');
                }}
                
                showAlert('正在启动后端OpenCV检测...', 'info');
                
                // 如果是远程设备，直接启动更新循环
                if (selectedDeviceInfo.isRemote) {{
                    document.getElementById('startBtn').disabled = true;
                    document.getElementById('stopBtn').disabled = false;
                    showAlert('远程设备检测已启动！', 'success');
                    startUpdateLoop();
                    return;
                }}
                
                // 本地设备：启动后端OpenCV检测
                console.log('🔍 正在调用 /api/start_camera...');
                console.log('🔍 请求URL:', '/api/start_camera');
                console.log('🔍 请求方法: POST');
                
                try {{
                    const response = await fetch('/api/start_camera', {{ method: 'POST' }});
                    console.log('🔍 HTTP响应状态:', response.status);
                    console.log('🔍 HTTP响应OK:', response.ok);
                    
                    const result = await response.json();
                    console.log('🔍 后端摄像头启动响应:', result);
                    console.log('🔍 响应状态字段:', result.status);
                    console.log('🔍 响应消息字段:', result.message);
                    console.log('🔍 camera_active字段:', result.camera_active);
                
                    if (result.status === 'success' || result.status === 'warning') {{
                        console.log('✅ 摄像头启动成功，开始UI更新...');
                        
                        console.log('🔍 更新启动按钮状态...');
                        const startBtn = document.getElementById('startBtn');
                        const stopBtn = document.getElementById('stopBtn');
                        if (startBtn) {{
                            startBtn.disabled = true;
                            console.log('✅ 启动按钮已禁用');
                        }}
                        if (stopBtn) {{
                            stopBtn.disabled = false;
                            console.log('✅ 停止按钮已启用');
                        }}
                        
                        // 显示摄像头窗口
                        console.log('🔍 显示摄像头窗口...');
                        const cameraWindow = document.getElementById('cameraWindow');
                        if (cameraWindow) {{
                            cameraWindow.style.display = 'block';
                            console.log('✅ 摄像头窗口已显示');
                        }} else {{
                            console.log('❌ 找不到摄像头窗口元素');
                        }}
                        
                        // 更新状态
                        console.log('🔍 更新摄像头状态...');
                        const cameraStatus = document.getElementById('cameraStatus');
                        if (cameraStatus) {{
                            cameraStatus.textContent = '在线 (后端OpenCV检测)';
                            cameraStatus.style.color = '#4CAF50';
                            console.log('✅ 摄像头状态已更新');
                        }} else {{
                            console.log('❌ 找不到摄像头状态元素');
                        }}
                        
                        showAlert('后端OpenCV检测启动成功！', 'success');
                        console.log('🔍 启动更新循环...');
                        startUpdateLoop();
                        console.log('✅ 摄像头启动流程完成');
                        
                    }} else {{
                        console.error('❌ 摄像头启动失败:', result);
                        console.error('❌ 失败状态:', result.status);
                        console.error('❌ 失败消息:', result.message);
                        showAlert('启动检测失败: ' + result.message, 'error');
                    }}
                    
                }} catch (fetchError) {{
                    console.error('❌ API调用异常:', fetchError);
                    console.error('❌ 异常详情:', fetchError.message);
                    console.error('❌ 异常堆栈:', fetchError.stack);
                    showAlert('API调用失败: ' + fetchError.message, 'error');
                }}
            }} catch (error) {{
                showAlert('启动失败: ' + error.message, 'error');
            }}
        }}
        

        
        async function stopCamera() {{
            try {{
                // 停止后端OpenCV检测
                await fetch('/api/stop_camera', {{ method: 'POST' }});
                
                document.getElementById('startBtn').disabled = false;
                document.getElementById('stopBtn').disabled = true;
                
                // 根据当前选择的设备更新状态
                if (selectedDeviceInfo && selectedDeviceInfo.isRemote) {{
                    document.getElementById('cameraStatus').textContent = '在线 (远程设备)';
                }} else if (selectedDeviceId) {{
                    document.getElementById('cameraStatus').textContent = '在线 (本地设备)';
                }} else {{
                    document.getElementById('cameraStatus').textContent = '离线';
                    document.getElementById('cameraWindow').style.display = 'none';
                }}
                
                // 清空人员检测数据
                document.getElementById('personCount').textContent = '0';
                map.remove(personMarkers);
                personMarkers = [];
                showAlert('后端检测已停止', 'success');
            }} catch (error) {{
                showAlert('停止失败: ' + error.message, 'error');
            }}
        }}
        
        function startUpdateLoop() {{
            // 🚀 优化：视频更新频率更高，数据更新频率适中
            setInterval(() => {{
                const cameraStatus = document.getElementById('cameraStatus');
                if (cameraStatus && cameraStatus.textContent.includes('在线')) {{
                    updateCameraFrame();
                }}
            }}, 500); // 每500ms更新视频显示
            
            setInterval(() => {{
                const cameraStatus = document.getElementById('cameraStatus');
                if (cameraStatus && cameraStatus.textContent.includes('在线')) {{
                    updatePersonsData();
                }}
            }}, 1500); // 每1.5秒更新人员数据
            
            // 🌟 更新移动设备数据
            setInterval(() => {{
                updateMobileDevicesData();
            }}, 2000); // 每2秒更新移动设备数据
        }}
        
        async function updateCameraFrame() {{
            try {{
                const response = await fetch('/api/get_camera_frame');
                const result = await response.json();
                if (result.status === 'success' && result.frame) {{
                    // 显示后端OpenCV处理的带检测框图像
                    console.log('🔍 开始更新视频显示...');
                    
                    const cameraImage = document.getElementById('cameraImage');
                    const cameraPlaceholder = document.getElementById('cameraPlaceholder');
                    
                    console.log('🔍 查找DOM元素结果:');
                    console.log('  - cameraImage:', cameraImage ? '找到' : '未找到');
                    console.log('  - cameraPlaceholder:', cameraPlaceholder ? '找到' : '未找到');
                    
                    if (cameraImage) {{
                        console.log('🔍 设置cameraImage.src:', result.frame.substring(0, 50) + '...');
                        cameraImage.src = result.frame;
                        cameraImage.style.display = 'block';
                        
                        // 确保摄像头窗口显示
                        const cameraWindow = document.getElementById('cameraWindow');
                        if (cameraWindow) {{
                            cameraWindow.style.display = 'block';
                            console.log('🎬 摄像头窗口已显示');
                        }}
                        
                        console.log('🔍 cameraImage样式设置完成, display:', cameraImage.style.display);
                        console.log('🔍 cameraImage当前状态:');
                        console.log('  - offsetWidth:', cameraImage.offsetWidth);
                        console.log('  - offsetHeight:', cameraImage.offsetHeight);
                        console.log('  - 父元素:', cameraImage.parentElement ? cameraImage.parentElement.tagName : '无');
                    }} else {{
                        console.error('❌ 找不到cameraImage元素！');
                        // 尝试查找所有可能的图像元素
                        const allImages = document.getElementsByTagName('img');
                        console.log('🔍 页面中所有img元素数量:', allImages.length);
                        for (let i = 0; i < allImages.length; i++) {{
                            console.log('  - img[' + i + '] id: "' + allImages[i].id + '", class: "' + allImages[i].className + '"');
                        }}
                    }}
                    
                    if (cameraPlaceholder) {{
                        cameraPlaceholder.style.display = 'none';
                        console.log('🔍 cameraPlaceholder已隐藏');
                    }} else {{
                        console.error('❌ 找不到cameraPlaceholder元素！');
                    }}
                    
                    console.log('✅ 后端检测图像已更新');
                }} else {{
                    // 后端检测失败时，显示错误状态
                    console.warn('⚠️ 后端检测获取失败:', result);
                    const cameraImage = document.getElementById('cameraImage');
                    const cameraPlaceholder = document.getElementById('cameraPlaceholder');
                    
                    if (cameraImage) {{
                        cameraImage.style.display = 'none';
                    }}
                    
                    if (cameraPlaceholder) {{
                        cameraPlaceholder.textContent = '后端检测暂时不可用，请检查摄像头连接...';
                        cameraPlaceholder.style.display = 'block';
                    }}
                }}
            }} catch (error) {{
                console.error('❌ 获取摄像头画面失败:', error);
                // 出错时显示错误信息
                const cameraPlaceholder = document.getElementById('cameraPlaceholder');
                if (cameraPlaceholder) {{
                    cameraPlaceholder.textContent = '连接后端检测服务失败';
                    cameraPlaceholder.style.display = 'block';
                }}
            }}
        }}
        
        async function updatePersonsData() {{
            try {{
                const response = await fetch('/api/get_persons_data');
                const persons = await response.json();
                
                console.log('🔍 获取到人员数据:', persons);
                console.log('📊 人员数量:', persons.length);
                
                // 确保personMarkers是数组
                if (!Array.isArray(personMarkers)) {{
                    personMarkers = [];
                    console.log('⚠️ personMarkers已重新初始化为空数组');
                }}
                
                // 清除所有现有标记（包括测试数据）
                if (personMarkers.length > 0) {{
                    console.log(`🧹 清除 ${{personMarkers.length}} 个旧标记`);
                    map.remove(personMarkers);
                    personMarkers = [];
                    console.log('🧹 已清除旧标记');
                }}
                
                if (persons && persons.length > 0) {{
                    // 显示真实检测数据
                    document.getElementById('personCount').textContent = persons.length;
                    
                    persons.forEach((person, index) => {{
                        console.log(`🎯 添加人员标记 ${{index + 1}}:`, person);
                        
                        var marker = new AMap.Marker({{
                            position: [person.lng, person.lat],
                            content: `<div style="
                                font-size: 28px; 
                                display: flex; 
                                align-items: center; 
                                justify-content: center;
                                width: 36px;
                                height: 36px;
                                background: rgba(255, 100, 100, 0.9);
                                border-radius: 50%;
                                border: 2px solid #ff6666;
                                box-shadow: 0 0 12px rgba(255, 100, 100, 0.7);
                                cursor: pointer;
                            ">🧑‍🌾</div>`,
                            offset: new AMap.Pixel(-18, -18),
                            title: `检测目标 ${{person.id}} - 距离: ${{person.distance.toFixed(1)}}m`
                        }});
                        
                        // 为人员标记添加点击事件
                        var personInfoWindow = new AMap.InfoWindow({{
                            isCustom: true,
                            content: createPersonInfoContent(person),
                            offset: new AMap.Pixel(0, -30)
                        }});
                        
                        marker.on('click', function() {{
                            personInfoWindow.open(map, marker.getPosition());
                        }});
                        
                        personMarkers.push(marker);
                        map.add(marker);
                        
                        console.log(`✅ 人员标记已添加: [${{person.lng}}, ${{person.lat}}]`);
                        
                        // 第一个人员标记添加后，地图自动定位
                        if (index === 0) {{
                            map.setCenter([person.lng, person.lat]);
                            map.setZoom(20);
                            console.log(`🎯 地图已定位到人员位置: [${{person.lng}}, ${{person.lat}}]`);
                        }}
                    }});
                    
                    console.log(`🗺️ 总共添加了 ${{personMarkers.length}} 个人员标记`);
                    
                }} else if (document.getElementById('cameraStatus').textContent === '在线') {{
                    // 摄像头在线但无检测到人员
                    document.getElementById('personCount').textContent = '0';
                    console.log('📷 摄像头在线，但未检测到人员');
                }} else {{
                    // 摄像头离线时重新添加测试数据
                    addTestPersons();
                    console.log('🔌 摄像头离线，显示测试数据');
                }}
            }} catch (error) {{
                console.error('❌ 获取人员数据失败:', error);
                console.error('❌ 错误详情:', error.stack);
                
                // 发生错误时确保数组状态正确
                if (!Array.isArray(personMarkers)) {{
                    personMarkers = [];
                }}
            }}
        }}
        
        // 添加调试函数
        async function debugInfo() {{
            try {{
                const response = await fetch('/api/debug_info');
                const debug = await response.json();
                console.log('🔧 调试信息:', debug);
                
                showAlert(`调试信息: 摄像头${{debug.camera_active ? '在线' : '离线'}}, 检测${{debug.detection_count}}人, 地图有${{debug.persons_count}}个标记`, 'info');
            }} catch (error) {{
                console.error('❌ 获取调试信息失败:', error);
            }}
        }}
        
        // 每5秒调用一次调试信息
        setInterval(debugInfo, 5000);
        
        // 系统诊断函数
        async function systemDiagnosis() {{
            console.log("=".repeat(80));
            console.log("🔧 系统诊断开始");
            console.log("=".repeat(80));
            
            // 1. 基础信息
            console.log("📊 基础系统信息:");
            console.log("  - 浏览器:", navigator.userAgent);
            console.log("  - 当前时间:", new Date().toLocaleString());
            console.log("  - 页面URL:", window.location.href);
            
            // 2. 设备选择状态
            console.log("📷 设备选择状态:");
            console.log("  - selectedDeviceId:", selectedDeviceId || '未选择');
            console.log("  - selectedDeviceInfo:", selectedDeviceInfo || '未选择');
            
            // 3. 按钮状态
            console.log("🎛️ 控制按钮状态:");
            const startBtn = document.getElementById('startBtn');
            const stopBtn = document.getElementById('stopBtn');
            console.log("  - 启动按钮:", startBtn ? (startBtn.disabled ? '禁用' : '启用') : '未找到');
            console.log("  - 停止按钮:", stopBtn ? (stopBtn.disabled ? '禁用' : '启用') : '未找到');
            
            // 4. 摄像头状态
            const cameraStatus = document.getElementById('cameraStatus');
            console.log("📹 摄像头状态:");
            console.log("  - 状态文本:", cameraStatus ? cameraStatus.textContent : '未找到状态元素');
            
            // 5. 后端API调用
            console.log("🌐 API调用测试:");
            try {{
                const response = await fetch('/api/debug_info');
                const debug = await response.json();
                console.log("  - debug_info API响应:", debug);
            }} catch (error) {{
                console.log("  - debug_info API错误:", error);
            }}
            
            try {{
                const frameResponse = await fetch('/api/get_camera_frame');
                const frameResult = await frameResponse.json();
                console.log("  - get_camera_frame API响应状态:", frameResult.status);
                console.log("  - get_camera_frame active:", frameResult.active);
                console.log("  - get_camera_frame 有帧数据:", !!frameResult.frame);
            }} catch (error) {{
                console.log("  - get_camera_frame API错误:", error);
            }}
            
            // 6. DOM元素检查
            console.log("🎨 DOM元素检查:");
            const cameraImage = document.getElementById('cameraImage');
            const cameraPlaceholder = document.getElementById('cameraPlaceholder');
            const cameraWindow = document.getElementById('cameraWindow');
            
            console.log("  - cameraImage元素:", cameraImage ? '存在' : '不存在');
            if (cameraImage) {{
                console.log("    - display:", cameraImage.style.display);
                console.log("    - offsetWidth:", cameraImage.offsetWidth);
                console.log("    - offsetHeight:", cameraImage.offsetHeight);
            }}
            
            console.log("  - cameraPlaceholder元素:", cameraPlaceholder ? '存在' : '不存在');
            if (cameraPlaceholder) {{
                console.log("    - display:", cameraPlaceholder.style.display);
                console.log("    - textContent:", cameraPlaceholder.textContent);
            }}
            
            console.log("  - cameraWindow元素:", cameraWindow ? '存在' : '不存在');
            if (cameraWindow) {{
                console.log("    - display:", cameraWindow.style.display);
            }}
            
            console.log("=".repeat(80));
            console.log("🔧 系统诊断完成 - 请查看以上详细信息");
            console.log("=".repeat(80));
            
            showAlert('系统诊断完成，请查看浏览器控制台详细信息', 'info');
        }}
        
        function showAlert(message, type) {{
            const alertBox = document.getElementById('alertBox');
            const alertMessage = document.getElementById('alertMessage');
            
            // 添加null检查
            if (!alertBox || !alertMessage) {{
                console.error('❌ 找不到alert元素');
                // 使用浏览器原生alert作为后备
                alert(message);
                return;
            }}
            
            alertMessage.textContent = message;
            alertBox.style.display = 'block';
            
            if (type === 'success') alertBox.style.borderColor = '#00aa00';
            else if (type === 'error') alertBox.style.borderColor = '#aa0000';
            else alertBox.style.borderColor = '#00aaff';
            
            setTimeout(() => {{ alertBox.style.display = 'none'; }}, 3000);
        }}
        
        // 🌟 检查移动端设备数据
        async function checkMobileDevices() {{
            try {{
                console.log('🔍 正在检查移动端设备数据...');
                showAlert('正在检查移动端设备连接状态...', 'info');
                
                const response = await fetch('/api/get_mobile_devices_data');
                const devicesData = await response.json();
                
                console.log('📱 检查结果:', devicesData);
                
                if (devicesData.length === 0) {{
                    showAlert('❌ 未发现移动端设备数据\\n请确保:\\n1. 移动端已连接\\n2. GPS权限已授予\\n3. 数据传输正常', 'error');
                    console.log('📋 移动端连接检查清单:');
                    console.log('  ✓ 移动端是否打开了客户端页面？');
                    console.log('  ✓ 移动端是否允许了GPS权限？');
                    console.log('  ✓ 移动端是否允许了朝向权限？');
                    console.log('  ✓ 移动端网络连接是否正常？');
                    console.log('  ✓ 服务器是否收到数据？(查看后台日志)');
                }} else {{
                    let summary = `✅ 发现 ${{devicesData.length}} 个移动设备:\\n`;
                    devicesData.forEach((device, index) => {{
                        const deviceId = device.device_id.substr(0, 8);
                        const hasLocation = device.location ? '✓GPS' : '✗GPS';
                        const hasOrientation = device.orientation ? '✓朝向' : '✗朝向';
                        summary += `${{index + 1}}. 设备${{deviceId}}: ${{hasLocation}} ${{hasOrientation}}\\n`;
                        
                        if (device.location) {{
                            summary += `   位置: (${{device.location.latitude.toFixed(4)}}, ${{device.location.longitude.toFixed(4)}})\\n`;
                        }}
                        if (device.orientation) {{
                            summary += `   朝向: ${{device.orientation.heading.toFixed(1)}}°\\n`;
                        }}
                    }});
                    
                    showAlert(summary, 'success');
                    
                    // 强制更新地图显示
                    console.log('🔄 强制更新地图显示...');
                    updateMobileDevicesData();
                }}
                
            }} catch (error) {{
                console.error('❌ 检查移动端设备失败:', error);
                showAlert('检查移动端设备失败: ' + error.message, 'error');
            }}
        }}
        
        // 远程视频流管理
        var remoteVideoInterval = null;
        var currentRemoteDeviceId = null;
        
        function startRemoteVideoStream(deviceId) {{
            console.log('🎬 开始接收远程视频流:', deviceId);
            currentRemoteDeviceId = deviceId;
            
            // 更新摄像头状态（添加null检查）
            const cameraStatus = document.getElementById('cameraStatus');
            if (cameraStatus) {{
                cameraStatus.textContent = '在线 (远程设备)';
                cameraStatus.style.color = '#4CAF50';
            }} else {{
                console.error('❌ 找不到摄像头状态元素');
            }}
            
            // 显示摄像头窗口（添加null检查）
            const cameraWindow = document.getElementById('cameraWindow');
            if (cameraWindow) {{
                cameraWindow.style.display = 'block';
            }} else {{
                console.error('❌ 找不到摄像头窗口元素');
            }}
            
            // 定期更新远程视频帧
            remoteVideoInterval = setInterval(() => {{
                updateRemoteVideoFrame(deviceId);
            }}, 1000); // 1秒更新一次
        }}
        
        function stopRemoteVideoStream() {{
            if (remoteVideoInterval) {{
                clearInterval(remoteVideoInterval);
                remoteVideoInterval = null;
            }}
            currentRemoteDeviceId = null;
            
            // 重置摄像头状态（添加null检查）
            const cameraStatus = document.getElementById('cameraStatus');
            if (cameraStatus) {{
                cameraStatus.textContent = '离线';
                cameraStatus.style.color = '#f44336';
            }} else {{
                console.error('❌ 找不到摄像头状态元素');
            }}
            
            // 隐藏摄像头窗口（添加null检查）
            const cameraWindow = document.getElementById('cameraWindow');
            if (cameraWindow) {{
                cameraWindow.style.display = 'none';
            }} else {{
                console.error('❌ 找不到摄像头窗口元素');
            }}
        }}
        
        async function updateRemoteVideoFrame(deviceId) {{
            try {{
                const response = await fetch(`/api/remote_device/stream/${{deviceId}}`);
                if (response.ok) {{
                    const result = await response.json();
                    if (result.status === 'success' && result.frame) {{
                        const remoteVideo = document.getElementById('remoteVideo');
                        if (remoteVideo) {{
                            // 创建图像元素来显示视频帧
                            const img = document.createElement('img');
                            img.src = result.frame;
                            img.style.width = '100%';
                            img.style.height = '100%';
                            img.style.objectFit = 'contain';
                            
                            // 替换视频内容
                            const cameraContent = document.querySelector('.camera-content');
                            cameraContent.innerHTML = '';
                            cameraContent.appendChild(img);
                        }}
                        
                        // 如果有GPS数据，自动调整地图位置
                        if (result.gps) {{
                            const {{ lat, lng }} = result.gps;
                            console.log(`📍 收到远程设备GPS数据: (${{lat}}, ${{lng}})`);
                            
                            // 自动调整地图中心到远程设备位置
                            map.setCenter([lng, lat]);
                            map.setZoom(19); // 设置适当的缩放级别
                            
                            // 添加或更新设备位置标记
                            updateRemoteDeviceMarker(deviceId, lat, lng);
                        }}
                    }}
                }} else {{
                    console.warn('获取远程视频帧失败:', response.status);
                }}
            }} catch (error) {{
                console.error('更新远程视频帧错误:', error);
            }}
        }}
        
        var remoteDeviceMarkers = {{}};
        
        function updateRemoteDeviceMarker(deviceId, lat, lng) {{
            // 移除旧的设备标记
            if (remoteDeviceMarkers[deviceId]) {{
                map.remove(remoteDeviceMarkers[deviceId]);
            }}
            
            // 添加新的设备标记
            const marker = new AMap.Marker({{
                position: [lng, lat],
                icon: new AMap.Icon({{
                    size: new AMap.Size(32, 32),
                    image: 'https://webapi.amap.com/theme/v1.3/markers/n/mark_b.png'  // 蓝色标记表示移动设备
                }}),
                title: `移动设备: ${{deviceId.substr(0, 8)}}...`
            }});
            
            // 添加设备信息窗口
            const deviceInfoWindow = new AMap.InfoWindow({{
                isCustom: true,
                content: createRemoteDeviceInfoContent(deviceId, lat, lng),
                offset: new AMap.Pixel(0, -30)
            }});
            
            marker.on('click', function() {{
                deviceInfoWindow.open(map, marker.getPosition());
            }});
            
            remoteDeviceMarkers[deviceId] = marker;
            map.add(marker);
            
            console.log(`📍 已更新远程设备标记: ${{deviceId.substr(0, 8)}}... 位置: (${{lat}}, ${{lng}})`);
        }}
        
        // 🌟 更新移动设备数据
        async function updateMobileDevicesData() {{
            try {{
                const response = await fetch('/api/get_mobile_devices_data');
                const devicesData = await response.json();
                
                // 🔧 修复：缓存设备数据供点击事件使用
                currentMobileDevicesData = devicesData;
                
                console.log('📱 获取到移动设备数据:', devicesData);
                console.log('📱 设备数量:', devicesData.length);
                
                // 🐛 调试信息
                if (devicesData.length === 0) {{
                    console.log('⚠️ 没有找到移动设备数据，可能原因:');
                    console.log('  1. 移动端还未连接');
                    console.log('  2. GPS权限未授予');
                    console.log('  3. 数据传输失败');
                    console.log('  4. 数据已过期(30秒)');
                }} else {{
                    devicesData.forEach((device, index) => {{
                        console.log(`📱 设备 ${{index + 1}}:`, {{
                            id: device.device_id.substr(0, 8),
                            hasLocation: !!device.location,
                            hasOrientation: !!device.orientation,
                            location: device.location,
                            orientation: device.orientation
                        }});
                    }});
                }}
                
                // 🔧 修复：清除过期的设备标记（移除对locationMarker的引用）
                for (let deviceId in mobileDeviceMarkers) {{
                    const hasCurrentData = devicesData.some(d => d.device_id === deviceId);
                    if (!hasCurrentData) {{
                        console.log(`🗑️ 清除过期设备标记: ${{deviceId.substr(0, 8)}}`);
                        if (mobileDeviceMarkers[deviceId].orientationMarker) {{
                            const oldOrientation = mobileDeviceMarkers[deviceId].orientationMarker;
                            if (oldOrientation.deviceMarker) {{
                                map.remove(oldOrientation.deviceMarker);
                            }}
                            if (oldOrientation.viewSector) {{
                                map.remove(oldOrientation.viewSector);
                            }}
                        }}
                        delete mobileDeviceMarkers[deviceId];
                    }}
                }}
                
                // 更新设备标记
                devicesData.forEach(device => {{
                    updateMobileDeviceMarker(device);
                }});
                
            }} catch (error) {{
                console.error('❌ 获取移动设备数据失败:', error);
            }}
        }}
        
        // 🌟 更新移动设备标记
        function updateMobileDeviceMarker(device) {{
            const deviceId = device.device_id;
            
            if (!mobileDeviceMarkers[deviceId]) {{
                mobileDeviceMarkers[deviceId] = {{}};
            }}
            
            // 🔧 修复：移除独立的位置标记，避免重复的无人机图标
            // 位置信息将通过朝向标记来显示，避免图标重复
            
            // 更新朝向标记
            if (device.location && device.orientation) {{
                const {{ latitude, longitude }} = device.location;
                const heading = device.orientation.heading;
                
                // 🔧 修复：正确移除旧的视野扇形标记，避免重叠
                if (mobileDeviceMarkers[deviceId].orientationMarker) {{
                    // orientationMarker是一个复合对象，包含deviceMarker和viewSector
                    const oldOrientation = mobileDeviceMarkers[deviceId].orientationMarker;
                    if (oldOrientation.deviceMarker) {{
                        map.remove(oldOrientation.deviceMarker);
                    }}
                    if (oldOrientation.viewSector) {{
                        map.remove(oldOrientation.viewSector);
                    }}
                }}
                
                // 创建视野扇形标记
                const orientationMarker = createOrientationArrow(longitude, latitude, heading, deviceId);
                mobileDeviceMarkers[deviceId].orientationMarker = orientationMarker;
                // 添加设备标记和视野扇形到地图
                map.add(orientationMarker.deviceMarker);
                map.add(orientationMarker.viewSector);
                
                console.log(`🔶 已更新移动设备视野扇形: ${{deviceId.substr(0, 8)}} ${{heading.toFixed(1)}}°`);
            }}
        }}
        
        // 🌟 创建朝向扇形标记 - 支持动态调节
        var sectorSize = 50;  // 扇形大小 (默认50px)
        var sectorAngle = 90; // 扇形角度 (默认90度)
        
        function createOrientationArrow(lng, lat, heading, deviceId) {{
            // 🌟 创建真实地理范围的视野扇形 
            const maxRange = sectorSize * 2; // 视野最大距离(米)
            const fovAngle = sectorAngle; // 视野角度
            
            // 首先创建设备位置标记
            const deviceMarkerHtml = `
                <div style="
                    width: 30px; height: 30px;
                    background: radial-gradient(circle, #FF9800, #FF6F00);
                    border-radius: 50%;
                    border: 3px solid white;
                    box-shadow: 0 0 15px rgba(255, 152, 0, 0.8);
                    animation: pulse 2s infinite;
                    position: relative;
                ">
                    <div style="
                        position: absolute;
                        top: 50%; left: 50%;
                        transform: translate(-50%, -50%);
                        font-size: 16px;
                    ">🚁</div>
                    <div style="
                        position: absolute;
                        top: -2px; left: 50%;
                        transform: translateX(-50%) rotate(${{heading}}deg);
                        width: 0; height: 0;
                        border-left: 6px solid transparent;
                        border-right: 6px solid transparent;
                        border-bottom: 20px solid #FF9800;
                        filter: drop-shadow(0 0 3px rgba(0,0,0,0.5));
                    "></div>
                </div>
            `;
            
            const deviceMarker = new AMap.Marker({{
                position: [lng, lat],
                content: deviceMarkerHtml,
                offset: new AMap.Pixel(-15, -15),
                title: `移动无人机: ${{heading.toFixed(1)}}° (视野:${{fovAngle}}°)`
            }});
            
            // 🔧 修复：为朝向标记添加点击事件，显示完整设备信息
            const deviceInfoWindow = new AMap.InfoWindow({{
                isCustom: true,
                content: '', // 内容将在点击时动态生成
                offset: new AMap.Pixel(0, -40)
            }});
            
            deviceMarker.on('click', function() {{
                // 动态生成设备信息内容
                // 需要从全局设备数据中获取完整信息
                const deviceData = getCurrentDeviceData(deviceId);
                if (deviceData) {{
                    deviceInfoWindow.setContent(createMobileDeviceInfoContent(deviceData));
                    deviceInfoWindow.open(map, deviceMarker.getPosition());
                }}
            }});
            
            // 🎯 创建真实的地理视野扇形
            const viewSector = createGeographicSector(lng, lat, heading, fovAngle, maxRange);
            
            // 返回一个包含设备标记和视野扇形的复合对象
            return {{
                deviceMarker: deviceMarker,
                viewSector: viewSector,
                // 为了兼容性，返回设备标记的方法
                getPosition: () => deviceMarker.getPosition(),
                setPosition: (pos) => {{
                    deviceMarker.setPosition(pos);
                    // 同时更新视野扇形位置
                    updateSectorPosition(viewSector, pos.getLng(), pos.getLat(), heading, fovAngle, maxRange);
                }},
                getTitle: () => deviceMarker.getTitle(),
                setTitle: (title) => deviceMarker.setTitle(title)
            }};
        }}
        
        // 🌍 创建地理坐标系的扇形视野
        function createGeographicSector(centerLng, centerLat, heading, fovAngle, range, color = '#FF9800') {{
            const points = [];
            const steps = 20; // 扇形分割精度
            
            // 添加中心点
            points.push([centerLng, centerLat]);
            
            // 计算扇形边界点
            const startAngle = heading - fovAngle / 2;
            const endAngle = heading + fovAngle / 2;
            
            for (let i = 0; i <= steps; i++) {{
                const angle = startAngle + (endAngle - startAngle) * i / steps;
                const point = calculateDestinationPoint(centerLat, centerLng, range, angle);
                points.push([point.lng, point.lat]);
            }}
            
            // 回到中心点闭合扇形
            points.push([centerLng, centerLat]);
            
            // 创建多边形覆盖物
            const sector = new AMap.Polygon({{
                path: points,
                strokeColor: color,
                strokeWeight: 2,
                strokeOpacity: 0.8,
                fillColor: color,
                fillOpacity: 0.2,
                bubble: true
            }});
            
            return sector;
        }}
        
        // 🧭 地理坐标计算：根据起点、距离、方位角计算目标点
        function calculateDestinationPoint(lat, lng, distance, bearing) {{
            const R = 6371000; // 地球半径(米)
            const lat1 = lat * Math.PI / 180;
            const lng1 = lng * Math.PI / 180;
            const bearingRad = bearing * Math.PI / 180;
            
            const lat2 = Math.asin(
                Math.sin(lat1) * Math.cos(distance / R) +
                Math.cos(lat1) * Math.sin(distance / R) * Math.cos(bearingRad)
            );
            
            const lng2 = lng1 + Math.atan2(
                Math.sin(bearingRad) * Math.sin(distance / R) * Math.cos(lat1),
                Math.cos(distance / R) - Math.sin(lat1) * Math.sin(lat2)
            );
            
            return {{
                lat: lat2 * 180 / Math.PI,
                lng: lng2 * 180 / Math.PI
            }};
        }}
        
        // 🔄 更新扇形位置
        function updateSectorPosition(sector, lng, lat, heading, fovAngle, range) {{
            const points = [];
            const steps = 20;
            
            points.push([lng, lat]);
            
            const startAngle = heading - fovAngle / 2;
            const endAngle = heading + fovAngle / 2;
            
            for (let i = 0; i <= steps; i++) {{
                const angle = startAngle + (endAngle - startAngle) * i / steps;
                const point = calculateDestinationPoint(lat, lng, range, angle);
                points.push([point.lng, point.lat]);
            }}
            
            points.push([lng, lat]);
            sector.setPath(points);
        }}
        
        // 🎛️ 扇形控制函数
        function adjustSectorSize(increment) {{
            sectorSize = Math.max(30, Math.min(100, sectorSize + increment));
            updateSectorDisplay();
            updateAllSectors();
            showAlert(`无人机视野大小: ${{sectorSize}}px`, 'info');
        }}
        
        function adjustSectorAngle(increment) {{
            sectorAngle = Math.max(30, Math.min(180, sectorAngle + increment));
            updateSectorDisplay();
            updateAllSectors();
            showAlert(`无人机视野角度: ${{sectorAngle}}°`, 'info');
        }}
        
        function setSectorPreset(size, angle) {{
            sectorSize = size;
            sectorAngle = angle;
            updateSectorDisplay();
            updateAllSectors();
            showAlert(`预设应用: ${{size}}px, ${{angle}}°`, 'success');
        }}
        
        function updateSectorDisplay() {{
            const sizeDisplay = document.getElementById('sectorSizeDisplay');
            const angleDisplay = document.getElementById('sectorAngleDisplay');
            if (sizeDisplay) sizeDisplay.textContent = `${{sectorSize}}px`;
            if (angleDisplay) angleDisplay.textContent = `${{sectorAngle}}°`;
        }}
        
        // 🔧 修复：获取当前设备数据
        function getCurrentDeviceData(deviceId) {{
            return currentMobileDevicesData.find(device => device.device_id === deviceId);
        }}
        
        function updateAllSectors() {{
            // 重新创建所有移动设备的扇形标记
            Object.keys(mobileDeviceMarkers).forEach(deviceId => {{
                const device = mobileDeviceMarkers[deviceId];
                if (device.orientationMarker) {{
                    const position = device.orientationMarker.getPosition();
                    const lng = position.getLng();
                    const lat = position.getLat();
                    
                    // 获取当前朝向
                    const title = device.orientationMarker.getTitle();
                    const headingMatch = title.match(/([0-9.]+)°/);
                    const heading = headingMatch ? parseFloat(headingMatch[1]) : 0;
                    
                    // 移除旧标记
                    map.remove(device.orientationMarker.deviceMarker);
                    map.remove(device.orientationMarker.viewSector);
                    
                    // 创建新标记
                    device.orientationMarker = createOrientationArrow(lng, lat, heading, deviceId);
                    map.add(device.orientationMarker.deviceMarker);
                    map.add(device.orientationMarker.viewSector);
                }}
            }});
        }}
        
        function createMobileDeviceInfoContent(device) {{
            const deviceId = device.device_id;
            const location = device.location;
            const orientation = device.orientation;
            const timeStr = new Date().toLocaleTimeString('zh-CN');
            
            let locationText = '未知位置';
            let orientationText = '朝向未知';
            let accuracyText = '';
            
            if (location) {{
                locationText = `${{location.latitude.toFixed(6)}}, ${{location.longitude.toFixed(6)}}`;
                accuracyText = `精度: ±${{location.accuracy}}m`;
            }}
            
            if (orientation) {{
                orientationText = `${{orientation.heading.toFixed(1)}}° (倾斜:${{orientation.tilt.toFixed(1)}}°)`;
            }}
            
            return `
                <div style="background: linear-gradient(135deg, #1976D2, #2196F3); color: white; padding: 15px; border-radius: 10px; box-shadow: 0 4px 15px rgba(0,0,0,0.3); font-family: Arial, sans-serif; min-width: 280px;">
                    <div style="display: flex; align-items: center; margin-bottom: 10px;">
                        <div style="width: 32px; height: 32px; background: #64B5F6; border-radius: 50%; display: flex; align-items: center; justify-content: center; margin-right: 10px;">
                            📱
                        </div>
                        <h3 style="margin: 0; color: #E3F2FD;">📱 移动摄像头</h3>
                    </div>
                    <div style="border-top: 1px solid rgba(255,255,255,0.3); padding-top: 10px;">
                        <p style="margin: 5px 0;"><strong>🆔 设备ID:</strong> ${{deviceId.substr(0, 12)}}...</p>
                        <p style="margin: 5px 0;"><strong>📍 GPS位置:</strong> ${{locationText}}</p>
                        <p style="margin: 5px 0;"><strong>🎯 位置精度:</strong> ${{accuracyText}}</p>
                        <p style="margin: 5px 0;"><strong>🔶 摄像头视野:</strong> ${{orientationText}}</p>
                        <p style="margin: 5px 0;"><strong>⏰ 更新时间:</strong> ${{timeStr}}</p>
                    </div>
                    <div style="text-align: center; margin-top: 10px; font-size: 12px; color: #cccccc;">
                        📹 实时移动侦察设备
                    </div>
                </div>
            `;
        }}
        
        function createRemoteDeviceInfoContent(deviceId, lat, lng) {{
            const deviceInfo = remoteDevices.find(d => d.device_id === deviceId);
            const deviceName = deviceInfo ? deviceInfo.device_name : '未知设备';
            const batteryLevel = deviceInfo ? deviceInfo.battery_level : '--';
            const timeStr = new Date().toLocaleTimeString('zh-CN');
            
            return `
                <div style="background: linear-gradient(135deg, #1976D2, #2196F3); color: white; padding: 15px; border-radius: 10px; box-shadow: 0 4px 15px rgba(0,0,0,0.3); font-family: Arial, sans-serif; min-width: 280px;">
                    <div style="display: flex; align-items: center; margin-bottom: 10px;">
                        <div style="width: 32px; height: 32px; background: #64B5F6; border-radius: 50%; display: flex; align-items: center; justify-content: center; margin-right: 10px;">
                            📱
                        </div>
                        <h3 style="margin: 0; color: #E3F2FD;">📱 移动设备</h3>
                    </div>
                    <div style="border-top: 1px solid rgba(255,255,255,0.3); padding-top: 10px;">
                        <p style="margin: 5px 0;"><strong>🆔 设备名称:</strong> ${{deviceName}}</p>
                        <p style="margin: 5px 0;"><strong>📍 坐标:</strong> ${{lat.toFixed(6)}}, ${{lng.toFixed(6)}}</p>
                        <p style="margin: 5px 0;"><strong>🔋 电池电量:</strong> ${{batteryLevel}}%</p>
                        <p style="margin: 5px 0;"><strong>📡 设备ID:</strong> ${{deviceId.substr(0, 16)}}...</p>
                        <p style="margin: 5px 0;"><strong>⏰ 更新时间:</strong> ${{timeStr}}</p>
                    </div>
                    <div style="text-align: center; margin-top: 10px; padding-top: 10px; border-top: 1px solid rgba(255,255,255,0.3);">
                        <div style="color: #E3F2FD; font-size: 12px;">📡 实时传输中</div>
                        <div style="color: #cccccc; font-size: 11px; margin-top: 5px;">点击其他区域关闭信息窗口</div>
                    </div>
                </div>
            `;
        }}
        
        window.onload = function() {{
            showAlert('🚁 系统已就绪，点击"侦察设备选择"开始监控', 'info');
            // 页面加载时显示测试数据
            addTestPersons();
            // 初始化设备管理
            initDeviceManagement();
        }};
        
        // ========== 设备选择功能 ==========
        
        var availableDevices = [];
        var selectedDeviceId = null;
        var selectedDeviceInfo = null;
        var currentStream = null;
        
        async function initDeviceManagement() {{
            console.log('📷 初始化设备管理系统');
            await scanDevices();
        }}
        
        async function scanDevices() {{
            console.log('🔍 扫描可用视频设备...');
            try {{
                if (!navigator.mediaDevices || !navigator.mediaDevices.enumerateDevices) {{
                    throw new Error('浏览器不支持设备枚举功能');
                }}

                const devices = await navigator.mediaDevices.enumerateDevices();
                availableDevices = devices.filter(device => device.kind === 'videoinput');
                
                console.log('✅ 发现 ' + availableDevices.length + ' 个视频设备', availableDevices);
                
            }} catch (error) {{
                console.error('❌ 设备扫描失败:', error);
                availableDevices = [];
            }}
        }}
        
        async function showDeviceSelector() {{
            console.log('📱 显示设备选择器');
            const selector = document.getElementById('deviceSelector');
            
            // 添加null检查
            if (!selector) {{
                console.error('❌ 找不到设备选择器元素');
                showAlert('设备选择器无法打开，请刷新页面重试', 'error');
                return;
            }}
            
            selector.style.display = 'flex';
            
            await scanDevices();
            await refreshRemoteDevices();
            updateDeviceList();
        }}
        
        function hideDeviceSelector() {{
            const deviceSelector = document.getElementById('deviceSelector');
            if (deviceSelector) {{
                deviceSelector.style.display = 'none';
            }} else {{
                console.error('❌ 找不到设备选择器元素');
            }}
            // 注意：不清空设备选择，因为设备已经成功启动
            // clearDeviceSelection(); // 注释掉这行，保持设备选择状态
        }}
        
        function cancelDeviceSelection() {{
            const deviceSelector = document.getElementById('deviceSelector');
            if (deviceSelector) {{
                deviceSelector.style.display = 'none';
            }} else {{
                console.error('❌ 找不到设备选择器元素');
            }}
            clearDeviceSelection(); // 取消时清空选择
        }}
        
        async function refreshDevices() {{
            document.getElementById('localDeviceList').innerHTML = '<div class="loading">正在扫描设备...</div>';
            document.getElementById('remoteDeviceList').innerHTML = '<div class="loading">正在获取远程设备...</div>';
            
            await scanDevices();
            await refreshRemoteDevices();
            updateDeviceList();
        }}
        
        function updateDeviceList() {{
            updateLocalDeviceList();
            updateRemoteDeviceList();
        }}
        
        function updateLocalDeviceList() {{
            const localList = document.getElementById('localDeviceList');
            
            if (availableDevices.length === 0) {{
                localList.innerHTML = '<div style="color: #ff6b6b; text-align: center; padding: 20px;">未发现本地摄像头设备<br><small>请确保已连接摄像头并允许浏览器访问</small></div>';
                return;
            }}

            localList.innerHTML = '';
            availableDevices.forEach((device, index) => {{
                console.log('🔍 处理设备 ' + index + ':', device);
                console.log('🔍 设备ID:', device.deviceId);
                console.log('🔍 设备标签:', device.label);
                console.log('🔍 设备完整对象:', JSON.stringify(device));
                
                // 首先确定设备类型
                const deviceName = device.label || `摄像头 ${{index + 1}}`;
                const isFrontCamera = deviceName.toLowerCase().includes('front') || deviceName.toLowerCase().includes('前');
                const isBackCamera = deviceName.toLowerCase().includes('back') || deviceName.toLowerCase().includes('后');
                const isVirtualCamera = deviceName.toLowerCase().includes('virtual') || 
                                      deviceName.toLowerCase().includes('obs') || 
                                      deviceName.toLowerCase().includes('虚拟');
                
                // 创建设备项并设置样式
                const deviceItem = document.createElement('div');
                deviceItem.className = 'device-item' + (isVirtualCamera ? ' virtual-device' : '');
                
                // 如果 deviceId 为空，使用索引作为临时ID
                const deviceId = device.deviceId || ('device_' + index);
                deviceItem.onclick = () => selectDevice(deviceId, {{
                    label: device.label || ('摄像头 ' + (index + 1)),
                    kind: device.kind,
                    isRemote: false,
                    deviceObject: device  // 保存完整的设备对象
                }});

                let cameraIcon = '📷';
                let deviceKind = '本地设备';
                if (isVirtualCamera) {{
                    cameraIcon = '🖥️';
                    deviceKind = '虚拟摄像头';
                }} else if (isFrontCamera) {{
                    cameraIcon = '🤳';
                }} else if (isBackCamera) {{
                    cameraIcon = '📹';
                }}

                deviceItem.innerHTML = 
                    '<div class="device-name">' + cameraIcon + ' ' + deviceName + '</div>' +
                    '<div class="device-id">' + device.deviceId + '</div>' +
                    '<div class="device-kind">' + deviceKind + '</div>';
                localList.appendChild(deviceItem);
            }});
        }}
        
        var remoteDevices = [];
        
        async function refreshRemoteDevices() {{
            try {{
                const response = await fetch('/api/mobile/devices');
                if (response.ok) {{
                    remoteDevices = await response.json();
                    console.log('🌐 获取到远程设备:', remoteDevices);
                    updateRemoteDeviceList();
                }} else {{
                    console.log('📡 无远程设备连接');
                    remoteDevices = [];
                    updateRemoteDeviceList();
                }}
            }} catch (error) {{
                console.error('❌ 获取远程设备失败:', error);
                remoteDevices = [];
                updateRemoteDeviceList();
            }}
        }}
        
        function updateRemoteDeviceList() {{
            const remoteList = document.getElementById('remoteDeviceList');
            
            if (remoteDevices.length === 0) {{
                remoteList.innerHTML = '<div style="color: #ccc; font-size: 12px; text-align: center; padding: 10px;">暂无远程设备连接<br><small>手机设备连接后将显示在这里</small></div>';
                return;
            }}
            
            remoteList.innerHTML = '';
            remoteDevices.forEach(device => {{
                const deviceItem = document.createElement('div');
                deviceItem.className = 'device-item';
                deviceItem.onclick = () => selectDevice(device.device_id, {{
                    label: device.device_name,
                    isRemote: true,
                    deviceInfo: device
                }});
                
                // 计算最后在线时间
                const lastSeen = new Date(device.last_seen * 1000);
                const now = new Date();
                const diffMinutes = Math.floor((now - lastSeen) / 60000);
                let timeText = '';
                if (diffMinutes < 1) timeText = '在线';
                else if (diffMinutes < 60) timeText = `${{diffMinutes}}分钟前`;
                else timeText = `${{Math.floor(diffMinutes / 60)}}小时前`;
                
                const batteryText = device.battery_level ? `${{device.battery_level}}%` : '--';
                const locationText = device.location ? `${{device.location.lat.toFixed(4)}}, ${{device.location.lng.toFixed(4)}}` : '未知位置';
                
                deviceItem.innerHTML = `
                    <div class="device-name">📱 ${{device.device_name}}</div>
                    <div class="device-id">${{device.device_id.substr(0, 8)}}...</div>
                    <div style="font-size: 11px; color: #ccc; margin-top: 3px;">
                        🔋 ${{batteryText}} | 📍 ${{locationText}}
                    </div>
                    <div style="font-size: 11px; color: #ccc;">⏰ ${{timeText}}</div>
                    <div class="device-kind" style="background: #ff9800;">移动设备</div>
                `;
                remoteList.appendChild(deviceItem);
            }});
        }}
        
        function selectDevice(deviceId, deviceInfo) {{
            console.log('🔍 selectDevice 被调用');
            console.log('🔍 传入的 deviceId:', deviceId);
            console.log('🔍 传入的 deviceInfo:', deviceInfo);
            
            // 清除之前的选择
            document.querySelectorAll('.device-item').forEach(item => {{
                item.classList.remove('selected');
            }});
            
            // 选择当前设备
            event.currentTarget.classList.add('selected');
            selectedDeviceId = deviceId;
            selectedDeviceInfo = deviceInfo;
            
            console.log('🔍 设置后的 selectedDeviceId:', selectedDeviceId);
            console.log('🔍 设置后的 selectedDeviceInfo:', selectedDeviceInfo);
            
            // 启用使用按钮
            const useBtn = document.getElementById('useDeviceBtn');
            useBtn.disabled = false;
            console.log('🔘 使用按钮已启用:', !useBtn.disabled);
            
            console.log('🎯 已选择设备: ' + deviceInfo.label);
            showAlert('已选择设备: ' + deviceInfo.label, 'info');
        }}
        
        function clearDeviceSelection() {{
            selectedDeviceId = null;
            selectedDeviceInfo = null;
            document.getElementById('useDeviceBtn').disabled = true;
            document.querySelectorAll('.device-item').forEach(item => {{
                item.classList.remove('selected');
            }});
        }}
        
        async function useSelectedDevice() {{
            console.log('🔥 useSelectedDevice 函数被调用');
            console.log('🔍 selectedDeviceId:', selectedDeviceId);
            console.log('🔍 selectedDeviceInfo:', selectedDeviceInfo);
            
            if (!selectedDeviceId || !selectedDeviceInfo) {{
                console.log('❌ 没有选择设备');
                showAlert('请先选择一个设备', 'error');
                return;
            }}

            try {{
                console.log('🚀 正在选择设备: ' + selectedDeviceInfo.label);
                showAlert('设备选择: ' + selectedDeviceInfo.label, 'info');
                
                // 🌟 自动启动GPS和朝向检测
                showAlert('正在自动配置设备位置和朝向...', 'info');
                await autoConfigureDeviceOnSelection();
                
                // 检查是否为远程设备
                if (selectedDeviceInfo.isRemote) {{
                    console.log('🌐 选择远程设备:', selectedDeviceInfo.label);
                    
                    // 连接到远程设备
                    const connectResponse = await fetch('/api/connect_remote_device', {{
                        method: 'POST',
                        headers: {{ 'Content-Type': 'application/json' }},
                        body: JSON.stringify({{ device_id: selectedDeviceId }})
                    }});
                    
                    if (!connectResponse.ok) {{
                        throw new Error('无法连接到远程设备');
                    }}
                    
                    // 更新摄像头状态
                    const cameraStatus = document.getElementById('cameraStatus');
                    if (cameraStatus) {{
                        cameraStatus.textContent = '在线 (远程设备)';
                        cameraStatus.style.color = '#4CAF50';
                    }}
                    
                }} else {{
                    // 本地设备：只保存设备ID，不启动前端视频流
                    console.log('📱 选择本地设备:', selectedDeviceInfo.label);
                    
                    // 更新摄像头状态
                    const cameraStatus = document.getElementById('cameraStatus');
                    if (cameraStatus) {{
                        cameraStatus.textContent = '在线 (本地设备)';
                        cameraStatus.style.color = '#4CAF50';
                    }}
                }}
                
                // 更新按钮状态和文本
                const deviceSelectBtn = document.getElementById('deviceSelectBtn');
                if (deviceSelectBtn) {{
                    if (selectedDeviceInfo && selectedDeviceInfo.label) {{
                        deviceSelectBtn.textContent = '📷 ' + selectedDeviceInfo.label;
                        deviceSelectBtn.style.background = 'linear-gradient(45deg, #00aa00, #00ff00)';
                        console.log('✅ 按钮文本已更新:', deviceSelectBtn.textContent);
                    }} else {{
                        deviceSelectBtn.textContent = '📷 设备已选择';
                        deviceSelectBtn.style.background = 'linear-gradient(45deg, #00aa00, #00ff00)';
                    }}
                }}
                
                // 启用开始按钮
                const startBtn = document.getElementById('startBtn');
                if (startBtn) {{
                    startBtn.disabled = false;
                    console.log('✅ 开始按钮已启用');
                }}
                
                hideDeviceSelector();
                
                showAlert('设备选择成功: ' + selectedDeviceInfo.label, 'success');
                console.log('✅ 设备选择成功: ' + selectedDeviceInfo.label);

            }} catch (error) {{
                console.error('❌ 设备选择详细错误:', error);
                console.error('❌ 尝试的设备ID:', selectedDeviceId);
                console.error('❌ 设备信息:', selectedDeviceInfo);
                
                let errorMsg = error.message || '设备选择失败';
                showAlert('设备选择失败: ' + errorMsg, 'error');
            }}
        }}
        
        // 🌟 设备选择时自动配置GPS和朝向
        async function autoConfigureDeviceOnSelection() {{
            try {{
                console.log('🤖 启动设备选择时的自动配置...');
                
                // 1. 自动请求GPS权限
                const gpsResult = await autoRequestGPSPermission();
                if (!gpsResult.success) {{
                    console.warn('⚠️ GPS获取失败，使用默认位置');
                    showAlert('GPS获取失败，将使用默认位置', 'warning');
                }}
                
                // 2. 自动请求朝向权限  
                const orientationResult = await autoRequestOrientationPermission();
                if (!orientationResult.success) {{
                    console.warn('⚠️ 朝向获取失败，使用默认朝向');
                    showAlert('朝向获取失败，将使用默认朝向', 'warning');
                }}
                
                // 3. 如果GPS和朝向都成功，自动配置摄像头
                if (gpsResult.success && orientationResult.success) {{
                    console.log('📍 GPS和朝向都获取成功，开始自动配置...');
                    await autoConfigureCamera();
                    showAlert('🎯 设备位置和朝向自动配置完成！', 'success');
                }} else if (gpsResult.success) {{
                    console.log('📍 仅GPS成功，使用默认朝向配置...');
                    // 使用GPS位置但默认朝向（面向北方）
                    await autoConfigureCameraWithGPSOnly();
                    showAlert('📍 设备位置配置完成（使用默认朝向）', 'info');
                }}
                
            }} catch (error) {{
                console.error('❌ 自动配置过程出错:', error);
                showAlert('自动配置遇到问题，可手动配置', 'warning');
            }}
        }}
        
        // 自动请求GPS权限（无用户交互）
        async function autoRequestGPSPermission() {{
            try {{
                console.log('📍 自动请求GPS权限...');
                
                if (!('geolocation' in navigator)) {{
                    throw new Error('设备不支持GPS定位');
                }}
                
                const options = {{
                    enableHighAccuracy: true,
                    timeout: 10000,
                    maximumAge: 30000
                }};
                
                const position = await new Promise((resolve, reject) => {{
                    navigator.geolocation.getCurrentPosition(
                        resolve,
                        reject,
                        options
                    );
                }});
                
                currentGPSLocation = {{
                    latitude: position.coords.latitude,
                    longitude: position.coords.longitude,
                    accuracy: position.coords.accuracy
                }};
                
                updateGPSStatus('success', 
                    `GPS: ${{position.coords.latitude.toFixed(6)}}, ${{position.coords.longitude.toFixed(6)}} (±${{position.coords.accuracy.toFixed(0)}}m)`);
                
                console.log('✅ GPS自动获取成功:', currentGPSLocation);
                return {{ success: true, location: currentGPSLocation }};
                
            }} catch (error) {{
                console.warn('⚠️ GPS自动获取失败:', error.message);
                updateGPSStatus('error', `GPS获取失败: ${{error.message}}`);
                return {{ success: false, error: error.message }};
            }}
        }}
        
        // 自动请求朝向权限（无用户交互）
        async function autoRequestOrientationPermission() {{
            try {{
                console.log('🧭 自动请求朝向权限...');
                
                // 检查设备朝向支持
                if (!window.DeviceOrientationEvent) {{
                    throw new Error('设备不支持朝向检测');
                }}
                
                // 对于iOS 13+，需要请求权限
                if (typeof DeviceOrientationEvent.requestPermission === 'function') {{
                    const permission = await DeviceOrientationEvent.requestPermission();
                    if (permission !== 'granted') {{
                        throw new Error('朝向权限被拒绝');
                    }}
                }}
                
                // 等待朝向数据
                const orientationData = await new Promise((resolve, reject) => {{
                    // 检测是否为桌面设备
                    const isMobile = /Android|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
                    const timeoutDuration = isMobile ? 8000 : 3000; // 桌面端3秒超时，移动端8秒
                    
                    console.log('🧭 设备类型:', isMobile ? '移动设备' : '桌面设备', '超时时间:', timeoutDuration + 'ms');
                    
                    const timeout = setTimeout(() => {{
                        window.removeEventListener('deviceorientation', orientationHandler);
                        const deviceType = isMobile ? '移动设备' : '桌面设备';
                        reject(new Error(`${{deviceType}}朝向检测超时，可能不支持朝向传感器`));
                    }}, timeoutDuration);
                    
                    function orientationHandler(event) {{
                        console.log('🧭 收到朝向事件:', event.alpha, event.beta, event.gamma);
                        if (event.alpha !== null && event.alpha !== undefined) {{
                            clearTimeout(timeout);
                            window.removeEventListener('deviceorientation', orientationHandler);
                            resolve(event);
                        }}
                    }}
                    
                    window.addEventListener('deviceorientation', orientationHandler);
                    console.log('🧭 开始监听设备朝向事件...');
                }});
                
                let heading = orientationData.alpha;
                if (heading !== null && heading !== undefined) {{
                    // 处理不同设备的朝向数据
                    if (heading < 0) heading += 360;
                    heading = Math.round(heading);
                    
                    currentDeviceHeading = heading;
                    updateHeadingStatus('success', `设备朝向: ${{heading}}°`);
                    
                    console.log('✅ 设备朝向自动获取成功:', heading);
                    return {{ success: true, heading: heading }};
                }} else {{
                    throw new Error('无法获取有效的朝向数据');
                }}
                
            }} catch (error) {{
                console.warn('⚠️ 朝向自动获取失败:', error.message);
                updateHeadingStatus('error', `朝向获取失败: ${{error.message}}`);
                return {{ success: false, error: error.message }};
            }}
        }}
        
        // 仅使用GPS配置摄像头（使用默认朝向）
        async function autoConfigureCameraWithGPSOnly() {{
            try {{
                if (!currentGPSLocation) {{
                    throw new Error('GPS位置未获取');
                }}
                
                console.log('📍 使用GPS位置配置摄像头...');
                console.log('📍 GPS数据:', currentGPSLocation);
                
                const configData = {{
                    gps_location: [currentGPSLocation.latitude, currentGPSLocation.longitude],
                    user_heading: 0,  // 默认朝向北方
                    apply_config: true
                }};
                
                console.log('📍 发送配置数据:', configData);
                
                const response = await fetch('/api/orientation/auto_configure', {{
                    method: 'POST',
                    headers: {{ 'Content-Type': 'application/json' }},
                    body: JSON.stringify(configData)
                }});
                
                console.log('📍 API响应状态:', response.status, response.statusText);
                
                const result = await response.json();
                console.log('📍 API响应数据:', result);
                
                if (result.success) {{
                    console.log('✅ GPS配置成功:', result);
                    showAlert('📍 摄像头位置已根据GPS自动配置', 'success');
                    
                    // 更新页面显示
                    if (result.camera_heading !== undefined) {{
                        document.getElementById('currentHeading').textContent = result.camera_heading + '°';
                    }}
                    if (result.gps_location) {{
                        console.log('📍 新摄像头位置:', result.gps_location);
                    }}
                }} else {{
                    throw new Error(result.error || result.message || '配置失败，无详细错误信息');
                }}
                
            }} catch (error) {{
                console.error('❌ GPS配置详细错误:', error);
                if (error.name === 'TypeError' && error.message.includes('fetch')) {{
                    showAlert('GPS配置失败: 网络连接错误，请检查服务器连接', 'error');
                }} else {{
                    showAlert('GPS配置失败: ' + error.message, 'error');
                }}
            }}
        }}
        
        // 切换高级配置面板
        function toggleAdvancedPanel() {{
            const panel = document.getElementById('advancedPanel');
            const btn = document.getElementById('advancedBtn');
            if (panel.style.display === 'none') {{
                panel.style.display = 'block';
                btn.textContent = '⚙️ 收起';
                btn.style.background = '#28a745';
            }} else {{
                panel.style.display = 'none';
                btn.textContent = '⚙️ 高级';
                btn.style.background = '#6c757d';
            }}
        }}
        
        // 开启扇形控制面板
        function openSectorControlPanel() {{
            const panel = document.getElementById('sectorControlPanel');
            panel.style.display = 'flex';
            updateSectorDisplay(); // 确保显示最新数据
            showAlert('🔶 打开视野调整面板', 'info');
        }}
        
        // 关闭扇形控制面板
        function closeSectorControlPanel() {{
            const panel = document.getElementById('sectorControlPanel');
            panel.style.display = 'none';
            showAlert('✅ 视野调整完成', 'success');
        }}
        
        // 更新GPS状态显示
        function updateGPSStatus(type, message) {{
            const gpsStatus = document.getElementById('gpsStatus');
            if (gpsStatus) {{
                // 简化状态文本以适应小空间
                let shortMessage = message.replace('GPS状态: ', '');
                if (shortMessage.length > 12) {{
                    shortMessage = shortMessage.substring(0, 12) + '...';
                }}
                gpsStatus.textContent = 'GPS: ' + shortMessage;
                
                // 更新颜色
                if (type === 'success') {{
                    gpsStatus.style.background = 'rgba(40, 167, 69, 0.3)';
                    gpsStatus.style.color = '#d4edda';
                }} else if (type === 'error') {{
                    gpsStatus.style.background = 'rgba(220, 53, 69, 0.3)';
                    gpsStatus.style.color = '#f8d7da';
                }} else {{
                    gpsStatus.style.background = 'rgba(255, 193, 7, 0.3)';
                    gpsStatus.style.color = '#fff3cd';
                }}
            }}
        }}
        
        // 更新朝向状态显示
        function updateHeadingStatus(type, message) {{
            const headingStatus = document.getElementById('headingStatus');
            if (headingStatus) {{
                // 简化状态文本以适应小空间
                let shortMessage = message.replace('朝向状态: ', '');
                if (shortMessage.length > 12) {{
                    shortMessage = shortMessage.substring(0, 12) + '...';
                }}
                headingStatus.textContent = '朝向: ' + shortMessage;
                
                // 更新颜色
                if (type === 'success') {{
                    headingStatus.style.background = 'rgba(40, 167, 69, 0.3)';
                    headingStatus.style.color = '#d4edda';
                }} else if (type === 'error') {{
                    headingStatus.style.background = 'rgba(220, 53, 69, 0.3)';
                    headingStatus.style.color = '#f8d7da';
                }} else {{
                    headingStatus.style.background = 'rgba(255, 193, 7, 0.3)';
                    headingStatus.style.color = '#fff3cd';
                }}
            }}
        }}

        // 添加测试人员数据（基于摄像头实际检测逻辑）
        function addTestPersons() {{
            // 精确的地理坐标距离转换函数
            function offsetPosition(baseLat, baseLng, distanceMeters, bearingDegrees) {{
                const earthRadius = 6378137; // 地球半径，单位：米
                const lat1 = baseLat * Math.PI / 180; // 基点纬度转弧度
                const lng1 = baseLng * Math.PI / 180; // 基点经度转弧度
                const d = distanceMeters / earthRadius; // 距离转角度弧度
                const bearing = bearingDegrees * Math.PI / 180; // 方位角转弧度
                
                const lat2 = Math.asin(Math.sin(lat1) * Math.cos(d) +
                                     Math.cos(lat1) * Math.sin(d) * Math.cos(bearing));
                const lng2 = lng1 + Math.atan2(Math.sin(bearing) * Math.sin(d) * Math.cos(lat1),
                                              Math.cos(d) - Math.sin(lat1) * Math.sin(lat2));
                
                return {{
                    lat: lat2 * 180 / Math.PI, // 转回度数
                    lng: lng2 * 180 / Math.PI
                }};
            }}
            
            // 基于摄像头实际检测范围生成测试目标
            // 摄像头朝向: {config.CAMERA_HEADING}°, 视场角: {config.CAMERA_FOV}°
            const cameraHeading = {config.CAMERA_HEADING}; // 摄像头朝向角度
            const cameraFOV = {config.CAMERA_FOV}; // 摄像头视场角
            const halfFOV = cameraFOV / 2;
            
            // 在摄像头视野范围内生成目标位置
            const bearing1 = cameraHeading - halfFOV + 15; // 视野左侧
            const bearing2 = cameraHeading + halfFOV - 15; // 视野右侧
            
            // 根据摄像头朝向和视野范围计算目标位置
            const pos1 = offsetPosition({config.CAMERA_LATITUDE}, {config.CAMERA_LONGITUDE}, 5, bearing1);   
            const pos2 = offsetPosition({config.CAMERA_LATITUDE}, {config.CAMERA_LONGITUDE}, 8, bearing2);  
            
            // 计算像素位置（基于视野角度在画面中的相对位置）
            const pixelX1 = Math.round({config.FRAME_WIDTH} * 0.3); // 画面左侧30%处
            const pixelX2 = Math.round({config.FRAME_WIDTH} * 0.7); // 画面右侧70%处
            const pixelY1 = Math.round({config.FRAME_HEIGHT} * 0.6); // 画面下方60%处
            const pixelY2 = Math.round({config.FRAME_HEIGHT} * 0.5); // 画面中部50%处
            
            var testPersons = [
                {{
                    id: "视野目标1", 
                    lat: pos1.lat, 
                    lng: pos1.lng, 
                    distance: 5.0, 
                    pixel_x: pixelX1, 
                    pixel_y: pixelY1, 
                    timestamp: Date.now() / 1000,
                    bearing: bearing1
                }},
                {{
                    id: "视野目标2", 
                    lat: pos2.lat, 
                    lng: pos2.lng, 
                    distance: 8.0, 
                    pixel_x: pixelX2, 
                    pixel_y: pixelY2, 
                    timestamp: Date.now() / 1000,
                    bearing: bearing2
                }}
            ];
            
            testPersons.forEach((person) => {{
                var marker = new AMap.Marker({{
                    position: [person.lng, person.lat],
                    content: `<div style="
                        font-size: 28px; 
                        display: flex; 
                        align-items: center; 
                        justify-content: center;
                        width: 36px;
                        height: 36px;
                        background: rgba(139, 69, 19, 0.9);
                        border-radius: 50%;
                        border: 2px solid #8B4513;
                        box-shadow: 0 0 12px rgba(139, 69, 19, 0.7);
                        cursor: pointer;
                    ">🧑‍🌾</div>`,
                    offset: new AMap.Pixel(-18, -18),
                    title: `${{person.id}} - 距离: ${{person.distance.toFixed(1)}}m`
                }});
                
                // 为测试标记也添加点击事件
                var testInfoWindow = new AMap.InfoWindow({{
                    isCustom: true,
                    content: createTestPersonInfoContent(person),
                    offset: new AMap.Pixel(0, -30)
                }});
                
                marker.on('click', function() {{
                    testInfoWindow.open(map, marker.getPosition());
                }});
                
                personMarkers.push(marker);
                map.add(marker);
            }});
            
            document.getElementById('personCount').textContent = testPersons.length + ' (测试数据)';
        }}
        
        // 创建测试人员信息内容
        function createTestPersonInfoContent(person) {{
            var detectionTime = new Date(person.timestamp * 1000);
            var timeStr = detectionTime.toLocaleTimeString('zh-CN');
            var bearing = calculateBearing({config.CAMERA_LATITUDE}, {config.CAMERA_LONGITUDE}, person.lat, person.lng);
            var direction = getDirectionName(bearing);
            
            return `
                <div style="background: linear-gradient(135deg, #4B0082, #8A2BE2); color: white; padding: 15px; border-radius: 10px; box-shadow: 0 4px 15px rgba(0,0,0,0.3); font-family: Arial, sans-serif; min-width: 280px;">
                    <div style="display: flex; align-items: center; margin-bottom: 10px;">
                        <div style="width: 32px; height: 32px; background: #DA70D6; border-radius: 50%; display: flex; align-items: center; justify-content: center; margin-right: 10px;">
                            🧪
                        </div>
                        <h3 style="margin: 0; color: #E6E6FA;">🧪 测试目标</h3>
                    </div>
                    <div style="border-top: 1px solid rgba(255,255,255,0.3); padding-top: 10px;">
                        <p style="margin: 5px 0;"><strong>🆔 标识:</strong> ${{person.id}}</p>
                        <p style="margin: 5px 0;"><strong>📍 坐标:</strong> ${{person.lat.toFixed(6)}}, ${{person.lng.toFixed(6)}}</p>
                        <p style="margin: 5px 0;"><strong>📏 距离:</strong> ${{person.distance.toFixed(1)}}米</p>
                        <p style="margin: 5px 0;"><strong>🧭 方向:</strong> ${{direction}} (${{bearing.toFixed(0)}}°)</p>
                        <p style="margin: 5px 0;"><strong>📺 像素位置:</strong> (${{Math.round(person.pixel_x)}}, ${{Math.round(person.pixel_y)}})</p>
                        <p style="margin: 5px 0;"><strong>⏰ 生成时间:</strong> ${{timeStr}}</p>
                    </div>
                    <div style="text-align: center; margin-top: 10px; padding-top: 10px; border-top: 1px solid rgba(255,255,255,0.3);">
                        <div style="color: #E6E6FA; font-size: 12px;">🧪 测试数据 - 启动摄像头后会被替换</div>
                        <div style="color: #cccccc; font-size: 11px; margin-top: 5px;">点击其他区域关闭信息窗口</div>
                    </div>
                </div>
            `;
        }}
        
        // ========== GPS和朝向检测功能 ==========
        
        // 全局变量
        let currentGPSLocation = null;
        let currentDeviceHeading = null;
        let gpsWatchId = null;
        let orientationWatchId = null;
        
        // 请求GPS权限和位置
        async function requestGPSPermission() {{
            const gpsBtn = document.getElementById('gpsBtn');
            const gpsStatus = document.getElementById('gpsStatus');
            
            try {{
                gpsBtn.disabled = true;
                gpsBtn.textContent = '📍 获取中...';
                
                updateGPSStatus('pending', 'GPS状态: 正在获取权限...');
                
                if (!('geolocation' in navigator)) {{
                    throw new Error('设备不支持GPS定位');
                }}
                
                const options = {{
                    enableHighAccuracy: true,
                    timeout: 15000,
                    maximumAge: 10000
                }};
                
                // 获取当前位置
                const position = await new Promise((resolve, reject) => {{
                    navigator.geolocation.getCurrentPosition(resolve, reject, options);
                }});
                
                currentGPSLocation = {{
                    latitude: position.coords.latitude,
                    longitude: position.coords.longitude,
                    accuracy: position.coords.accuracy
                }};
                
                // 更新UI
                updateGPSStatus('success', `GPS状态: 已获取 (±${{Math.round(position.coords.accuracy)}}m)`);
                
                gpsBtn.textContent = '📍 位置已获取';
                gpsBtn.style.background = 'linear-gradient(135deg, #28a745, #20c997)';
                
                // 发送位置到服务器
                await fetch('/api/orientation/update_location', {{
                    method: 'POST',
                    headers: {{ 'Content-Type': 'application/json' }},
                    body: JSON.stringify(currentGPSLocation)
                }});
                
                console.log('✅ GPS位置已获取:', currentGPSLocation);
                checkAutoConfigReady();
                
            }} catch (error) {{
                console.error('❌ GPS获取失败:', error);
                
                let errorMsg = error.message;
                if (error.code === 1) errorMsg = '用户拒绝了位置权限';
                else if (error.code === 2) errorMsg = '位置信息不可用';
                else if (error.code === 3) errorMsg = '位置获取超时';
                
                updateGPSStatus('error', `GPS状态: 获取失败 - ${{errorMsg}}`);
                
                gpsBtn.textContent = '📍 重新获取';
                gpsBtn.style.background = 'linear-gradient(135deg, #dc3545, #c82333)';
                
            }} finally {{
                gpsBtn.disabled = false;
            }}
        }}
        
        // 请求设备朝向权限
        async function requestOrientationPermission() {{
            const orientationBtn = document.getElementById('orientationBtn');
            const headingStatus = document.getElementById('headingStatus');
            
            try {{
                orientationBtn.disabled = true;
                orientationBtn.textContent = '🧭 获取中...';
                
                updateHeadingStatus('pending', '朝向状态: 正在获取权限...');
                
                // 检查设备朝向API支持
                if (!('DeviceOrientationEvent' in window)) {{
                    throw new Error('设备不支持朝向检测');
                }}
                
                // 对于需要权限的浏览器（iOS 13+）
                if (typeof DeviceOrientationEvent.requestPermission === 'function') {{
                    const permission = await DeviceOrientationEvent.requestPermission();
                    if (permission !== 'granted') {{
                        throw new Error('朝向权限被拒绝');
                    }}
                }}
                
                // 开始监听设备朝向
                let hasReceived = false;
                const timeout = setTimeout(() => {{
                    if (!hasReceived) {{
                        throw new Error('朝向数据获取超时');
                    }}
                }}, 10000);
                
                const handleOrientation = (event) => {{
                    if (hasReceived) return;
                    
                    clearTimeout(timeout);
                    hasReceived = true;
                    
                    // 获取罗盘朝向（需要处理不同浏览器的差异）
                    let heading = event.alpha;
                    if (heading === null || heading === undefined) {{
                        heading = event.webkitCompassHeading || 0;
                    }}
                    
                    // 标准化角度
                    heading = ((heading % 360) + 360) % 360;
                    currentDeviceHeading = heading;
                    
                    // 更新UI
                    updateHeadingStatus('success', `朝向状态: 已获取 (${{Math.round(heading)}}°)`);
                    
                    orientationBtn.textContent = '🧭 朝向已获取';
                    orientationBtn.style.background = 'linear-gradient(135deg, #28a745, #20c997)';
                    
                    // 发送朝向到服务器
                    fetch('/api/orientation/update_heading', {{
                        method: 'POST',
                        headers: {{ 'Content-Type': 'application/json' }},
                        body: JSON.stringify({{ heading: heading }})
                    }});
                    
                    console.log('✅ 设备朝向已获取:', heading);
                    checkAutoConfigReady();
                    
                    // 移除监听器
                    window.removeEventListener('deviceorientation', handleOrientation);
                }};
                
                window.addEventListener('deviceorientation', handleOrientation);
                
            }} catch (error) {{
                console.error('❌ 朝向获取失败:', error);
                
                updateHeadingStatus('error', `朝向状态: 获取失败 - ${{error.message}}`);
                
                orientationBtn.textContent = '🧭 重新获取';
                orientationBtn.style.background = 'linear-gradient(135deg, #dc3545, #c82333)';
                
            }} finally {{
                orientationBtn.disabled = false;
            }}
        }}
        
        // 检查是否可以自动配置
        function checkAutoConfigReady() {{
            const autoConfigBtn = document.getElementById('autoConfigBtn');
            
            if (currentGPSLocation) {{
                autoConfigBtn.disabled = false;
                autoConfigBtn.style.background = 'linear-gradient(135deg, #28a745, #20c997)';
                autoConfigBtn.style.cursor = 'pointer';
                autoConfigBtn.textContent = '🤖 自动配置摄像头';
            }}
        }}
        
        // 自动配置摄像头
        async function autoConfigureCamera() {{
            const autoConfigBtn = document.getElementById('autoConfigBtn');
            
            try {{
                autoConfigBtn.disabled = true;
                autoConfigBtn.textContent = '🤖 配置中...';
                
                if (!currentGPSLocation) {{
                    throw new Error('请先获取GPS位置');
                }}
                
                showAlert('正在自动配置摄像头...', 'info');
                
                const configData = {{
                    gps: currentGPSLocation,
                    orientation: currentDeviceHeading ? {{ heading: currentDeviceHeading }} : null
                }};
                
                const response = await fetch('/api/orientation/auto_configure', {{
                    method: 'POST',
                    headers: {{ 'Content-Type': 'application/json' }},
                    body: JSON.stringify(configData)
                }});
                
                const result = await response.json();
                
                if (result.status === 'success') {{
                    // 更新页面显示的配置
                    const currentHeading = document.getElementById('currentHeading');
                    if (currentHeading && result.data.camera_heading !== undefined) {{
                        currentHeading.textContent = `${{Math.round(result.data.camera_heading)}}°`;
                    }}
                    
                    showAlert('✅ 摄像头配置成功！位置和朝向已自动设置', 'success');
                    
                    // 更新地图摄像头位置（如果需要）
                    if (result.data.gps_location) {{
                        const [lat, lng] = result.data.gps_location;
                        const newPosition = [lng, lat];
                        
                        // 更新摄像头标记位置
                        cameraMarker.setPosition(newPosition);
                        map.setCenter(newPosition);
                        
                        // 🔧 修复：同步更新视野扇形位置，避免图标重叠
                        if (fixedCameraFOV) {{
                            // 移除旧的视野扇形
                            map.remove(fixedCameraFOV);
                            
                            // 重新创建视野扇形在新位置
                            const newFOV = createGeographicSector(
                                lng, lat, 
                                result.data.camera_heading || {config.CAMERA_HEADING}, 
                                {config.CAMERA_FOV}, 
                                100,  // 100米检测范围
                                '#2196F3'  // 蓝色，与固定摄像头标记颜色匹配
                            );
                            map.add(newFOV);
                            
                            // 更新全局变量引用
                            fixedCameraFOV = newFOV;
                        }}
                        
                        console.log('✅ 地图摄像头位置和视野已更新');
                    }}
                    
                }} else {{
                    throw new Error(result.message || '配置失败');
                }}
                
            }} catch (error) {{
                console.error('❌ 自动配置失败:', error);
                showAlert('❌ 自动配置失败: ' + error.message, 'error');
                
            }} finally {{
                autoConfigBtn.disabled = false;
                autoConfigBtn.textContent = '🤖 自动配置摄像头';
            }}
        }}
        
        // 手动配置
        function manualConfiguration() {{
            showAlert('打开手动配置工具', 'info');
            
            // 可以打开配置页面或模态框
            const userLat = prompt('请输入摄像头纬度 (例: 39.9042):');
            const userLng = prompt('请输入摄像头经度 (例: 116.4074):');
            const userHeading = prompt('请输入摄像头朝向角度 (0-360°, 0为正北):');
            
            if (userLat && userLng && userHeading) {{
                const lat = parseFloat(userLat);
                const lng = parseFloat(userLng);
                const heading = parseFloat(userHeading);
                
                if (!isNaN(lat) && !isNaN(lng) && !isNaN(heading) && 
                    lat >= -90 && lat <= 90 && lng >= -180 && lng <= 180 &&
                    heading >= 0 && heading <= 360) {{
                    
                    // 模拟配置数据
                    currentGPSLocation = {{ latitude: lat, longitude: lng, accuracy: 1000 }};
                    currentDeviceHeading = heading;
                    
                    // 🔧 修复：手动配置时也要同步更新视野扇形
                    // 更新摄像头位置和朝向
                    cameraMarker.setPosition([lng, lat]);
                    map.setCenter([lng, lat]);
                    
                    // 同步更新视野扇形
                    if (fixedCameraFOV) {{
                        map.remove(fixedCameraFOV);
                        
                        const newFOV = createGeographicSector(
                            lng, lat, heading, {config.CAMERA_FOV}, 
                            100, '#2196F3'
                        );
                        map.add(newFOV);
                        fixedCameraFOV = newFOV;
                    }}
                    
                    // 更新显示
                    const currentHeading = document.getElementById('currentHeading');
                    if (currentHeading) {{
                        currentHeading.textContent = `${{Math.round(heading)}}°`;
                    }}
                    
                    showAlert('✅ 手动配置已应用到地图', 'success');
                    
                    autoConfigureCamera();
                }} else {{
                    showAlert('❌ 输入的数据格式不正确', 'error');
                }}
            }}
        }}
        
        // 页面加载时的初始化
        window.addEventListener('load', function() {{
            console.log('🧭 朝向检测系统已加载');
            
            // 检查浏览器支持
            if ('geolocation' in navigator) {{
                console.log('✅ 浏览器支持GPS');
            }} else {{
                console.log('❌ 浏览器不支持GPS');
                document.getElementById('gpsBtn').disabled = true;
                document.getElementById('gpsStatus').textContent = 'GPS状态: 浏览器不支持';
            }}
            
            if ('DeviceOrientationEvent' in window) {{
                console.log('✅ 浏览器支持设备朝向');
            }} else {{
                console.log('❌ 浏览器不支持设备朝向');
                document.getElementById('orientationBtn').disabled = true;
                document.getElementById('headingStatus').textContent = '朝向状态: 浏览器不支持';
            }}
        }});
    </script>
</body>
</html>"""
        return html_template
    
    def run(self, host='127.0.0.1', port=5000, debug=False, ssl_enabled=True):
        """启动Web服务器"""
        print("🌐 启动Web服务器...")
        
        ssl_context = None
        protocol = "http"
        
        if ssl_enabled:
            import os
            cert_file = "ssl/cert.pem"
            key_file = "ssl/key.pem"
            
            if os.path.exists(cert_file) and os.path.exists(key_file):
                ssl_context = (cert_file, key_file)
                protocol = "https"
                print("🔒 HTTPS模式已启用")
            else:
                print("⚠️  SSL证书文件不存在，正在生成...")
                self.generate_ssl_certificate()
                if os.path.exists(cert_file) and os.path.exists(key_file):
                    ssl_context = (cert_file, key_file)
                    protocol = "https"
                    print("🔒 HTTPS模式已启用")
                else:
                    print("❌ SSL证书生成失败，使用HTTP模式")
                    ssl_enabled = False
        
        print(f"📍 访问地址: {protocol}://{host}:{port}")
        if ssl_enabled:
            print("🔑 注意: 自签名证书会显示安全警告，点击'高级'->'继续访问'即可")
        print("🚁 无人机战场态势感知系统已就绪")
        
        try:
            self.app.run(host=host, port=port, debug=debug, threaded=True, ssl_context=ssl_context)
        except KeyboardInterrupt:
            print("\n🔴 服务器已停止")
            self.stop_camera_detection() 
            self.stop_camera_detection() 
    
    def generate_ssl_certificate(self):
        """生成自签名SSL证书"""
        try:
            import os
            import datetime
            import ipaddress
            from cryptography import x509
            from cryptography.x509.oid import NameOID
            from cryptography.hazmat.primitives import hashes, serialization
            from cryptography.hazmat.primitives.asymmetric import rsa
            
            # 创建ssl目录
            ssl_dir = "ssl"
            if not os.path.exists(ssl_dir):
                os.makedirs(ssl_dir)
            
            print("🔑 正在生成SSL证书...")
            
            # 生成私钥
            private_key = rsa.generate_private_key(
                public_exponent=65537,
                key_size=2048,
            )
            
            # 创建证书主体
            subject = issuer = x509.Name([
                x509.NameAttribute(NameOID.COUNTRY_NAME, "CN"),
                x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, "Beijing"),
                x509.NameAttribute(NameOID.LOCALITY_NAME, "Beijing"),
                x509.NameAttribute(NameOID.ORGANIZATION_NAME, "Distance Judgement System"),
                x509.NameAttribute(NameOID.COMMON_NAME, "localhost"),
            ])
            
            # 生成证书
            cert = x509.CertificateBuilder().subject_name(
                subject
            ).issuer_name(
                issuer
            ).public_key(
                private_key.public_key()
            ).serial_number(
                x509.random_serial_number()
            ).not_valid_before(
                datetime.datetime.utcnow()
            ).not_valid_after(
                datetime.datetime.utcnow() + datetime.timedelta(days=365)
            ).add_extension(
                x509.SubjectAlternativeName([
                    x509.DNSName("localhost"),
                    x509.DNSName("127.0.0.1"),
                    x509.IPAddress(ipaddress.IPv4Address("127.0.0.1")),
                ]),
                critical=False,
            ).sign(private_key, hashes.SHA256())
            
            # 保存私钥
            key_path = os.path.join(ssl_dir, "key.pem")
            with open(key_path, "wb") as f:
                f.write(private_key.private_bytes(
                    encoding=serialization.Encoding.PEM,
                    format=serialization.PrivateFormat.PKCS8,
                    encryption_algorithm=serialization.NoEncryption()
                ))
            
            # 保存证书
            cert_path = os.path.join(ssl_dir, "cert.pem")
            with open(cert_path, "wb") as f:
                f.write(cert.public_bytes(serialization.Encoding.PEM))
            
            print(f"✅ SSL证书已生成:")
            print(f"   🔑 私钥: {key_path}")
            print(f"   📜 证书: {cert_path}")
            print(f"   📅 有效期: 365天")
            
        except ImportError:
            print("❌ 缺少cryptography库，请先安装: pip install cryptography")
        except Exception as e:
            print(f"❌ 生成SSL证书失败: {e}") 
