#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ 平衡体态检测系统 - 后端服务 基于Flask的本地API服务 """ import os import sys import json import time import threading from datetime import datetime from flask import Flask, jsonify, send_file from flask import request as flask_request from flask_cors import CORS import sqlite3 import logging from pathlib import Path from flask_socketio import SocketIO, emit import cv2 import configparser import os # 添加当前目录到Python路径 sys.path.append(os.path.dirname(os.path.abspath(__file__))) # 导入自定义模块 from database import DatabaseManager from device_manager import DeviceManager, VideoStreamManager from utils import config as app_config # 配置日志 logging.basicConfig( level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', handlers=[ logging.FileHandler('logs/backend.log', encoding='utf-8'), logging.StreamHandler() ] ) logger = logging.getLogger(__name__) # 创建Flask应用 app = Flask(__name__) app.config['SECRET_KEY'] = 'body-balance-detection-system-2024' socketio = SocketIO(app, cors_allowed_origins='*', async_mode='threading', logger=True, engineio_logger=True) # 启用CORS支持 CORS(app, origins='*', supports_credentials=True, allow_headers=['Content-Type', 'Authorization'], methods=['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS']) # 注册Blueprint(如需要可在此处添加) # 读取RTSP配置 config = configparser.ConfigParser() config.read(os.path.join(os.path.dirname(__file__), '..', 'config.ini'), encoding='utf-8') device_index = config.get('CAMERA', 'device_index', fallback=None) # 全局变量 db_manager = None device_manager = None current_detection = None detection_thread = None video_stream_manager = None def init_app(): """初始化应用""" global db_manager, device_manager, video_stream_manager try: # 创建必要的目录 os.makedirs('logs', exist_ok=True) os.makedirs('data', exist_ok=True) # 从配置文件读取数据库路径 db_path_config = app_config.get('DATABASE', 'path', 'backend/data/body_balance.db') # 如果是相对路径,基于当前脚本目录解析 if not os.path.isabs(db_path_config): # 获取当前脚本所在目录(backend目录) current_dir = os.path.dirname(os.path.abspath(__file__)) # 如果配置路径以 'backend/' 开头,去掉这个前缀 if db_path_config.startswith('backend/'): db_path_config = db_path_config[8:] # 去掉 'backend/' 前缀 db_path = os.path.join(current_dir, db_path_config) else: db_path = db_path_config # 确保数据库目录存在 db_dir = os.path.dirname(db_path) os.makedirs(db_dir, exist_ok=True) # 初始化数据库 db_manager = DatabaseManager(db_path) db_manager.init_database() # 初始化设备管理器 device_manager = DeviceManager(db_manager) device_manager.set_socketio(socketio) # 设置WebSocket连接 # 初始化视频流管理器 video_stream_manager = VideoStreamManager(socketio) logger.info('应用初始化完成') except Exception as e: logger.error(f'应用初始化失败: {e}') raise # ==================== 基础API ==================== @app.route('/health', methods=['GET']) def health_check(): """健康检查""" return jsonify({ 'status': 'ok', 'timestamp': datetime.now().isoformat(), 'version': '1.0.0' }) @app.route('/api/health', methods=['GET']) def api_health_check(): """API健康检查""" return jsonify({ 'status': 'ok', 'timestamp': datetime.now().isoformat(), 'version': '1.0.0' }) # ==================== 认证API ==================== @app.route('/api/auth/login', methods=['POST']) def login(): """用户登录""" try: data = flask_request.get_json() username = data.get('username') password = data.get('password') remember = data.get('remember', False) if not username or not password: return jsonify({ 'success': False, 'message': '用户名或密码不能为空' }), 400 # 使用数据库验证用户 user = db_manager.authenticate_user(username, password) if user: # 检查用户是否已激活 if not user['is_active']: return jsonify({ 'success': False, 'message': '账户未激活,请联系管理员审核' }), 403 # 构建用户数据 user_data = { 'id': user['id'], 'username': user['username'], 'name': user['name'], 'role': 'admin' if user['user_type'] == 'admin' else 'user', 'user_type': user['user_type'], 'avatar': '' } # 生成token(实际项目中应使用JWT等安全token) token = f"token_{username}_{int(time.time())}" logger.info(f'用户 {username} 登录成功') return jsonify({ 'success': True, 'data': { 'token': token, 'user': user_data }, 'message': '登录成功' }) else: logger.warning(f'用户 {username} 登录失败:用户名或密码错误') return jsonify({ 'success': False, 'message': '用户名或密码错误' }), 401 except Exception as e: logger.error(f'登录失败: {e}') return jsonify({'success': False, 'message': '登录失败'}), 500 @app.route('/api/auth/register', methods=['POST']) def register(): """用户注册""" try: data = flask_request.get_json() username = data.get('username') password = data.get('password') name = data.get('name') or data.get('email', '') phone = data.get('phone') if not username or not password: return jsonify({ 'success': False, 'message': '用户名和密码不能为空' }), 400 if len(password) < 6: return jsonify({ 'success': False, 'message': '密码长度不能少于6位' }), 400 # 构建用户数据字典 user_data = { 'username': username, 'password': password, 'name': name, 'phone': phone } # 使用数据库注册用户 result = db_manager.register_user(user_data) if result['success']: logger.info(f'用户 {username} 注册成功,等待管理员审核') return jsonify({ 'success': True, 'message': '注册成功,请等待管理员审核后登录' }) else: return jsonify({ 'success': False, 'message': result['message'] }), 400 except Exception as e: logger.error(f'注册失败: {e}') return jsonify({'success': False, 'message': '注册失败'}), 500 @app.route('/api/auth/logout', methods=['POST']) def logout(): """用户退出""" try: return jsonify({ 'success': True, 'message': '退出成功' }) except Exception as e: logger.error(f'退出失败: {e}') return jsonify({'success': False, 'message': '退出失败'}), 500 @app.route('/api/auth/verify', methods=['GET']) def verify_token(): """验证token""" try: # 简单的token验证(实际项目中应验证JWT等) auth_header = flask_request.headers.get('Authorization') if auth_header and auth_header.startswith('Bearer '): token = auth_header.split(' ')[1] # 这里可以添加真实的token验证逻辑 return jsonify({ 'success': True, 'data': {'valid': True} }) else: return jsonify({ 'success': True, 'data': {'valid': True} # 暂时总是返回有效 }) except Exception as e: logger.error(f'验证token失败: {e}') return jsonify({'success': False, 'message': '验证失败'}), 500 @app.route('/api/auth/forgot-password', methods=['POST']) def forgot_password(): """忘记密码 - 根据用户名和手机号找回密码""" try: data = flask_request.get_json() username = data.get('username') phone = data.get('phone') if not username: return jsonify({ 'success': False, 'error': '请输入用户名' }), 400 if not phone: return jsonify({ 'success': False, 'error': '请输入手机号码' }), 400 # 验证手机号格式 import re phone_pattern = r'^1[3-9]\d{9}$' if not re.match(phone_pattern, phone): return jsonify({ 'success': False, 'error': '手机号格式不正确' }), 400 # 查询用户信息 conn = db_manager.get_connection() cursor = conn.cursor() cursor.execute(''' SELECT username, password, phone FROM users WHERE username = ? AND phone = ? ''', (username, phone)) user = cursor.fetchone() if user: # 用户存在且手机号匹配,返回数据库中存储的实际密码 actual_password = user['password'] logger.info(f'用户 {username} 密码查询成功') return jsonify({ 'success': True, 'password': actual_password, # 返回数据库中存储的实际密码 'message': '密码找回成功' }) else: # 检查用户是否存在 cursor.execute('SELECT username FROM users WHERE username = ?', (username,)) user_exists = cursor.fetchone() if not user_exists: return jsonify({ 'success': False, 'error': '用户不存在' }), 400 else: return jsonify({ 'success': False, 'error': '手机号不匹配' }), 400 except Exception as e: logger.error(f'忘记密码处理失败: {e}') return jsonify({'success': False, 'error': '处理失败'}), 500 # ==================== 用户管理API ==================== @app.route('/api/users', methods=['GET']) def get_users(): """获取用户列表(管理员功能)""" try: # 这里应该验证管理员权限 page = int(flask_request.args.get('page', 1)) size = int(flask_request.args.get('size', 10)) status = flask_request.args.get('status') # active, inactive, all users = db_manager.get_users(page, size, status) total = db_manager.get_users_count(status) return jsonify({ 'success': True, 'data': { 'users': users, 'total': total, 'page': page, 'size': size } }) except Exception as e: logger.error(f'获取用户列表失败: {e}') return jsonify({'success': False, 'message': '获取用户列表失败'}), 500 @app.route('/api/users//approve', methods=['POST']) def approve_user(user_id): """审核用户(管理员功能)""" try: # 这里应该验证管理员权限 data = flask_request.get_json() approve = data.get('approve', True) result = db_manager.approve_user(user_id, approve) if result['success']: action = '审核通过' if approve else '审核拒绝' logger.info(f'用户 {user_id} {action}') return jsonify({ 'success': True, 'message': f'用户{action}成功' }) else: return jsonify({ 'success': False, 'message': result['message'] }), 400 except Exception as e: logger.error(f'审核用户失败: {e}') return jsonify({'success': False, 'message': '审核用户失败'}), 500 @app.route('/api/users/', methods=['DELETE']) def delete_user(user_id): """删除用户(管理员功能)""" try: # 这里应该验证管理员权限 result = db_manager.delete_user(user_id) if result['success']: logger.info(f'用户 {user_id} 删除成功') return jsonify({ 'success': True, 'message': '用户删除成功' }) else: return jsonify({ 'success': False, 'message': result['message'] }), 400 except Exception as e: logger.error(f'删除用户失败: {e}') return jsonify({'success': False, 'message': '删除用户失败'}), 500 @app.route('/api/system/info', methods=['GET']) def get_system_info(): """获取系统信息""" try: info = { 'version': '1.0.0', 'start_time': datetime.now().isoformat(), 'database_status': 'connected' if db_manager else 'disconnected', 'device_count': len(device_manager.get_connected_devices()) if device_manager else 0 } return jsonify({'success': True, 'data': info}) except Exception as e: logger.error(f'获取系统信息失败: {e}') return jsonify({'success': False, 'error': str(e)}), 500 # ==================== 患者管理API ==================== @app.route('/api/patients', methods=['GET']) def get_patients(): """获取患者列表""" try: page = int(flask_request.args.get('page', 1)) size = int(flask_request.args.get('size', 10)) keyword = flask_request.args.get('keyword', '') patients = db_manager.get_patients(page, size, keyword) total = db_manager.get_patients_count(keyword) return jsonify({ 'success': True, 'data': { 'patients': patients, 'total': total, 'page': page, 'size': size } }) except Exception as e: logger.error(f'获取患者列表失败: {e}') return jsonify({'success': False, 'error': str(e)}), 500 @app.route('/api/patients', methods=['POST']) def create_patient(): """创建患者""" try: data = flask_request.get_json() patient_id = db_manager.create_patient(data) return jsonify({ 'success': True, 'data': {'patient_id': patient_id}, 'message': '患者创建成功' }) except Exception as e: logger.error(f'创建患者失败: {e}') return jsonify({'success': False, 'error': str(e)}), 500 @app.route('/api/patients/', methods=['PUT']) def update_patient(patient_id): """更新患者信息""" try: data = flask_request.get_json() db_manager.update_patient(patient_id, data) return jsonify({'success': True, 'message': '患者信息更新成功'}) except Exception as e: logger.error(f'更新患者信息失败: {e}') return jsonify({'success': False, 'error': str(e)}), 500 @app.route('/api/patients/', methods=['GET']) def get_patient(patient_id): """获取单个患者信息""" try: patient = db_manager.get_patient(patient_id) if patient: return jsonify({'success': True, 'data': patient}) else: return jsonify({'success': False, 'error': '患者不存在'}), 404 except Exception as e: logger.error(f'获取患者信息失败: {e}') return jsonify({'success': False, 'error': str(e)}), 500 @app.route('/api/patients/', methods=['DELETE']) def delete_patient(patient_id): """删除患者""" try: db_manager.delete_patient(patient_id) return jsonify({'success': True, 'message': '患者删除成功'}) except Exception as e: logger.error(f'删除患者失败: {e}') return jsonify({'success': False, 'error': str(e)}), 500 # ==================== 设备管理API ==================== @app.route('/api/devices/status', methods=['GET']) def get_device_status(): """获取设备状态""" try: if not device_manager: return jsonify({'camera': False, 'imu': False, 'pressure': False}) status = device_manager.get_device_status() return jsonify(status) except Exception as e: logger.error(f'获取设备状态失败: {e}') return jsonify({'camera': False, 'imu': False, 'pressure': False}) @app.route('/api/devices/refresh', methods=['POST']) def refresh_devices(): """刷新设备连接""" try: if device_manager: device_manager.refresh_devices() return jsonify({'success': True, 'message': '设备已刷新'}) except Exception as e: logger.error(f'刷新设备失败: {e}') return jsonify({'success': False, 'error': str(e)}), 500 @app.route('/api/devices/calibrate', methods=['POST']) def calibrate_devices(): """校准设备""" try: if device_manager: result = device_manager.calibrate_devices() return jsonify({'success': True, 'data': result}) return jsonify({'success': False, 'error': '设备管理器未初始化'}), 500 except Exception as e: logger.error(f'设备校准失败: {e}') return jsonify({'success': False, 'error': str(e)}), 500 # ==================== 视频推流API ==================== @app.route('/api/streaming/start', methods=['POST']) def start_video_streaming(): """启动视频推流""" try: if not device_manager: return jsonify({'success': False, 'error': '设备管理器未初始化'}), 500 # 设置WebSocket连接 device_manager.set_socketio(socketio) result = device_manager.start_streaming() logger.info(f'视频推流启动结果: {result}') return jsonify({ 'success': True, 'message': '视频推流已启动', 'streaming_status': result }) except Exception as e: logger.error(f'启动视频推流失败: {e}') return jsonify({'success': False, 'error': str(e)}), 500 @app.route('/api/streaming/stop', methods=['POST']) def stop_video_streaming(): """停止视频推流""" try: if not device_manager: return jsonify({'success': False, 'error': '设备管理器未初始化'}), 500 result = device_manager.stop_streaming() if result: logger.info('视频推流已停止') return jsonify({ 'success': True, 'message': '视频推流已停止' }) else: return jsonify({ 'success': False, 'error': '停止推流失败' }), 500 except Exception as e: logger.error(f'停止视频推流失败: {e}') return jsonify({'success': False, 'error': str(e)}), 500 # ==================== 检测API ==================== @app.route('/api/detection/start', methods=['POST']) def start_detection(): """开始检测""" try: if not db_manager: return jsonify({'success': False, 'error': '数据库管理器未初始化'}), 500 data = flask_request.get_json() patient_id = data.get('patientId') or data.get('patient_id') settings = data.get('settings', '{}') creator_id = data.get('creator_id') if not patient_id: return jsonify({ 'success': False, 'error': '缺少必要参数: patient_id' }), 400 # 解析设置参数 if isinstance(settings, str): try: settings = json.loads(settings) except json.JSONDecodeError: settings = {} # 创建检测会话 session_id = db_manager.create_detection_session( patient_id=str(patient_id), settings=settings, creator_id=creator_id ) if session_id: logger.info(f'检测会话已创建 - 会话ID: {session_id}, 患者ID: {patient_id}') return jsonify({ 'success': True, 'session_id': session_id, 'message': '检测会话创建成功' }) else: return jsonify({ 'success': False, 'error': '创建检测会话失败' }), 500 except Exception as e: logger.error(f'开始检测失败: {e}') return jsonify({'success': False, 'error': str(e)}), 500 @app.route('/api/detection//stop', methods=['POST']) def stop_detection(session_id): """停止检测""" try: if not db_manager: return jsonify({'success': False, 'error': '数据库管理器未初始化'}), 500 if not session_id: return jsonify({ 'success': False, 'error': '缺少会话ID' }), 400 # 更新会话状态为已完成 success = db_manager.update_session_status(session_id, 'completed') if success: logger.info(f'检测会话已停止 - 会话ID: {session_id}') return jsonify({ 'success': True, 'message': '检测已停止' }) else: return jsonify({ 'success': False, 'error': '停止检测失败' }), 500 except Exception as e: logger.error(f'停止检测失败: {e}') return jsonify({'success': False, 'error': str(e)}), 500 @app.route('/api/detection//status', methods=['GET']) def get_detection_status(session_id): """获取检测状态""" try: if not db_manager: return jsonify({'success': False, 'error': '数据库管理器未初始化'}), 500 if not session_id: return jsonify({ 'success': False, 'error': '缺少会话ID' }), 400 # 获取会话数据 session_data = db_manager.get_session_data(session_id) if session_data: return jsonify({ 'success': True, 'data': session_data }) else: return jsonify({ 'success': False, 'error': '会话不存在' }), 404 except Exception as e: logger.error(f'获取检测状态失败: {e}') return jsonify({'success': False, 'error': str(e)}), 500 @app.route('/api/detection//collect', methods=['POST']) def collect_detection_data(session_id): """采集检测数据""" try: if not db_manager: return jsonify({'success': False, 'error': '数据库管理器未初始化'}), 500 if not device_manager: return jsonify({'success': False, 'error': '设备管理器未初始化'}), 500 # 获取请求数据 data = flask_request.get_json() or {} patient_id = data.get('patient_id') screen_image_base64 = data.get('screen_image') # 如果没有提供patient_id,从会话信息中获取 if not patient_id: session_data = db_manager.get_session_data(session_id) if not session_data: return jsonify({ 'success': False, 'error': '检测会话不存在' }), 404 patient_id = session_data.get('patient_id') if not patient_id: return jsonify({ 'success': False, 'error': '无法获取患者ID' }), 400 # 调用设备管理器采集数据 collected_data = device_manager.collect_data( session_id=session_id, patient_id=patient_id, screen_image_base64=screen_image_base64 ) # 将采集的数据保存到数据库 if collected_data: db_manager.save_detection_data(session_id, collected_data) logger.info(f'检测数据采集并保存成功: {session_id}') return jsonify({ 'success': True, 'data': { 'session_id': session_id, 'timestamp': collected_data.get('timestamp'), 'data_collected': bool(collected_data) }, 'message': '数据采集成功' }) except Exception as e: logger.error(f'采集检测数据失败: {e}') return jsonify({'success': False, 'error': str(e)}), 500 # ==================== 同步录制API ==================== @app.route('/api/recording/sync/start', methods=['POST']) def start_sync_recording(): """启动同步录制""" try: if not device_manager: return jsonify({'success': False, 'error': '设备管理器未初始化'}), 500 data = flask_request.get_json() session_id = data.get('session_id') patient_id = data.get('patient_id') if not session_id or not patient_id: return jsonify({ 'success': False, 'error': '缺少必要参数: session_id 和 patient_id' }), 400 result = device_manager.start_recording(session_id, patient_id) if result['success']: logger.info(f'同步录制已启动 - 会话ID: {session_id}, 患者ID: {patient_id}') return jsonify(result) else: return jsonify(result), 500 except Exception as e: logger.error(f'启动同步录制失败: {e}') return jsonify({'success': False, 'error': str(e)}), 500 @app.route('/api/recording/sync/stop', methods=['POST']) def stop_sync_recording(): """停止同步录制""" try: if not device_manager: return jsonify({'success': False, 'error': '设备管理器未初始化'}), 500 data = flask_request.get_json() session_id = data.get('session_id') if not session_id: return jsonify({ 'success': False, 'error': '缺少必要参数: session_id' }), 400 result = device_manager.stop_recording(session_id) if result['success']: logger.info(f'同步录制已停止 - 会话ID: {session_id}') return jsonify(result) else: return jsonify(result), 500 except Exception as e: logger.error(f'停止同步录制失败: {e}') return jsonify({'success': False, 'error': str(e)}), 500 @app.route('/api/history/sessions', methods=['GET']) def get_detection_sessions(): """获取检测会话历史""" try: page = int(flask_request.args.get('page', 1)) size = int(flask_request.args.get('size', 10)) patient_id = flask_request.args.get('patient_id') sessions = db_manager.get_detection_sessions(page, size, patient_id) total = db_manager.get_sessions_count(patient_id) return jsonify({ 'success': True, 'data': { 'sessions': sessions, 'total': total, 'page': page, 'size': size } }) except Exception as e: logger.error(f'获取检测历史失败: {e}') return jsonify({'success': False, 'error': str(e)}), 500 # ==================== 错误处理 ==================== @app.errorhandler(404) def not_found(error): return jsonify({'success': False, 'error': 'API接口不存在'}), 404 @app.errorhandler(500) def internal_error(error): return jsonify({'success': False, 'error': '服务器内部错误'}), 500 if __name__ == '__main__': import argparse # 解析命令行参数 parser = argparse.ArgumentParser(description='Body Balance Evaluation System Backend') parser.add_argument('--host', default=None, help='Host address to bind to') parser.add_argument('--port', type=int, default=None, help='Port number to bind to') parser.add_argument('--debug', action='store_true', help='Enable debug mode') args = parser.parse_args() try: # 初始化应用 init_app() # 确定主机和端口 host = args.host if args.host else config.get('SERVER', 'host', fallback='127.0.0.1') port = args.port if args.port else config.getint('SERVER', 'port', fallback=5000) debug = args.debug if args.debug else config.getboolean('APP', 'debug', fallback=False) # 启动Flask+SocketIO服务 logger.info(f'启动后端服务... Host: {host}, Port: {port}, Debug: {debug}') socketio.run(app, host=host, port=port, debug=debug, use_reloader=False, # 禁用热重载以避免进程问题 log_output=True, # 启用详细日志 allow_unsafe_werkzeug=True ) except KeyboardInterrupt: logger.info('服务被用户中断') except Exception as e: logger.error(f'服务启动失败: {e}') sys.exit(1) finally: logger.info('后端服务已停止') # ==================== WebSocket 事件处理 ==================== # 简单的测试事件处理器 @socketio.on('connect') def handle_connect(): print('CLIENT CONNECTED!!!', flush=True) logger.info('客户端已连接') @socketio.on('disconnect') def handle_disconnect(): print('CLIENT DISCONNECTED!!!', flush=True) logger.info('客户端已断开连接') # @socketio.on('start_video') # def handle_start_video_new(data=None): # print('=== START VIDEO EVENT RECEIVED ===', flush=True) # print(f'Data received: {data}', flush=True) # logger.info('=== START VIDEO EVENT RECEIVED ===') # logger.info(f'Data received: {data}') # emit('video_status', {'status': 'received', 'message': 'start_video事件已接收'}) # return {'status': 'success'} # 原始的start_video处理逻辑(暂时注释) @socketio.on('start_video') def handle_start_video(data=None): try: results = {'status': 'success', 'cameras': {}} logger.info(f'video_stream_manager状态: {video_stream_manager is not None}') logger.info(f'device_manager状态: {device_manager is not None}') # 启动视频流管理器(普通摄像头) if video_stream_manager: logger.info('正在启动视频流管理器...') video_result = video_stream_manager.start_video_stream() logger.info(f'视频流管理器启动结果: {video_result}') results['cameras']['normal'] = video_result else: logger.error('视频流管理器未初始化') results['cameras']['normal'] = {'status': 'error', 'message': '视频流管理器未初始化'} # 启动FemtoBolt深度相机 if device_manager: logger.info('正在启动FemtoBolt深度相机...') femtobolt_result = device_manager.start_femtobolt_stream() logger.info(f'FemtoBolt启动结果: {femtobolt_result}') if femtobolt_result: results['cameras']['femtobolt'] = {'status': 'success', 'message': 'FemtoBolt深度相机推流已启动'} else: results['cameras']['femtobolt'] = {'status': 'error', 'message': 'FemtoBolt深度相机启动失败'} else: logger.error('设备管理器未初始化') results['cameras']['femtobolt'] = {'status': 'error', 'message': '设备管理器未初始化'} # 检查是否有任何相机启动成功 success_count = sum(1 for cam_result in results['cameras'].values() if cam_result.get('status') == 'success') if success_count == 0: results['status'] = 'error' results['message'] = '所有相机启动失败' elif success_count < len(results['cameras']): results['status'] = 'partial' results['message'] = f'{success_count}/{len(results["cameras"])}个相机启动成功' else: results['message'] = '所有相机启动成功' logger.info(f'发送video_status事件: {results}') emit('video_status', results) except Exception as e: logger.error(f'启动视频流失败: {e}', exc_info=True) emit('video_status', {'status': 'error', 'message': f'启动失败: {str(e)}'}) @socketio.on('stop_video') def handle_stop_video(data=None): logger.info(f'收到stop_video事件,数据: {data}') try: results = {'status': 'success', 'cameras': {}} # 停止视频流管理器(普通摄像头) if video_stream_manager: video_result = video_stream_manager.stop_video_stream() results['cameras']['normal'] = video_result else: results['cameras']['normal'] = {'status': 'error', 'message': '视频流管理器未初始化'} # 停止FemtoBolt深度相机 if device_manager: device_manager.stop_femtobolt_stream() results['cameras']['femtobolt'] = {'status': 'success', 'message': 'FemtoBolt深度相机推流已停止'} else: results['cameras']['femtobolt'] = {'status': 'error', 'message': '设备管理器未初始化'} # 检查是否有任何相机停止成功 success_count = sum(1 for cam_result in results['cameras'].values() if cam_result.get('status') == 'success') if success_count == 0: results['status'] = 'error' results['message'] = '所有相机停止失败' elif success_count < len(results['cameras']): results['status'] = 'partial' results['message'] = f'{success_count}/{len(results["cameras"])}个相机停止成功' else: results['message'] = '所有相机停止成功' emit('video_status', results) except Exception as e: logger.error(f'停止视频流失败: {e}') emit('video_status', {'status': 'error', 'message': f'停止失败: {str(e)}'}) # 重复的事件处理器已删除,使用前面定义的版本