From dd695cfccaf39030b4bbac27ab5048f52cbf3f8b Mon Sep 17 00:00:00 2001 From: zhaozilong12 <405241463@qq.com> Date: Tue, 29 Jul 2025 16:44:17 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/app.py | 66 ++++++++++++++++--- backend/config.ini | 4 ++ frontend/src/renderer/src/views/Dashboard.vue | 2 +- frontend/src/renderer/src/views/Detection.vue | 59 ++++++++++++----- 4 files changed, 107 insertions(+), 24 deletions(-) diff --git a/backend/app.py b/backend/app.py index 3dc87b24..6c5780e1 100644 --- a/backend/app.py +++ b/backend/app.py @@ -16,6 +16,10 @@ from flask_cors import CORS import sqlite3 import logging from pathlib import Path +from flask_socketio import SocketIO, emit +import cv2 +import base64 +import configparser # 添加当前目录到Python路径 sys.path.append(os.path.dirname(os.path.abspath(__file__))) @@ -40,10 +44,16 @@ 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') # 启用CORS支持 CORS(app, origins=['http://localhost:3000', 'http://localhost:3001', 'file://*']) +# 读取RTSP配置 +config = configparser.ConfigParser() +config.read(os.path.join(os.path.dirname(__file__), 'config.ini'), encoding='utf-8') +rtsp_url = config.get('CAMERA', 'rtsp_url', fallback=None) + # 全局变量 db_manager = None device_manager = None @@ -51,6 +61,8 @@ detection_engine = None data_processor = None current_detection = None detection_thread = None +rtsp_thread = None +rtsp_running = False def init_app(): """初始化应用""" @@ -612,19 +624,57 @@ if __name__ == '__main__': # 初始化应用 init_app() - # 启动Flask服务 + # 启动Flask+SocketIO服务 logger.info('启动后端服务...') - app.run( - host='127.0.0.1', - port=5000, - debug=False, - threaded=True + socketio.run(app, + host=config.get('SERVER', 'host', fallback='127.0.0.1'), + port=config.getint('SERVER', 'port', fallback=5000), + debug=config.getboolean('APP', 'debug', fallback=False), + allow_unsafe_werkzeug=True ) - except KeyboardInterrupt: logger.info('服务被用户中断') except Exception as e: logger.error(f'服务启动失败: {e}') sys.exit(1) finally: - logger.info('后端服务已停止') \ No newline at end of file + logger.info('后端服务已停止') + +# ==================== WebSocket 实时推送RTSP帧 ==================== + +def generate_rtsp_frames(): + global rtsp_running + cap = cv2.VideoCapture(rtsp_url) + if not cap.isOpened(): + logger.error(f'无法打开RTSP流: {rtsp_url}') + return + rtsp_running = True + while rtsp_running: + ret, frame = cap.read() + if not ret: + logger.warning('RTSP读取帧失败,尝试重连...') + cap.release() + time.sleep(1) + cap = cv2.VideoCapture(rtsp_url) + continue + _, buffer = cv2.imencode('.jpg', frame) + jpg_as_text = base64.b64encode(buffer).decode('utf-8') + socketio.emit('rtsp_frame', {'image': jpg_as_text}) + time.sleep(1/15) # 推送帧率可调 + cap.release() + +@socketio.on('start_rtsp') +def handle_start_rtsp(): + global rtsp_thread, rtsp_running + if rtsp_thread and rtsp_thread.is_alive(): + emit('rtsp_status', {'status': 'already_running'}) + return + rtsp_thread = threading.Thread(target=generate_rtsp_frames) + rtsp_thread.start() + emit('rtsp_status', {'status': 'started'}) + +@socketio.on('stop_rtsp') +def handle_stop_rtsp(): + global rtsp_running + rtsp_running = False + emit('rtsp_status', {'status': 'stopped'}) \ No newline at end of file diff --git a/backend/config.ini b/backend/config.ini index cb814776..3a3cfa8b 100644 --- a/backend/config.ini +++ b/backend/config.ini @@ -39,3 +39,7 @@ secret_key = 026efbf83a2fe101f168780740da86bf1c9260625458e6782738aa9cf18f8e37 session_timeout = 3600 max_login_attempts = 5 + +[CAMERA] +rtsp_url = rtsp://admin:password@192.168.1.100:554/Streaming/Channels/101 + diff --git a/frontend/src/renderer/src/views/Dashboard.vue b/frontend/src/renderer/src/views/Dashboard.vue index 3fa0f899..197d4735 100644 --- a/frontend/src/renderer/src/views/Dashboard.vue +++ b/frontend/src/renderer/src/views/Dashboard.vue @@ -265,7 +265,7 @@ const formatDate = (date) => { const loadPatients = async () => { try { - const response = await patientAPI.getList() + const response = await patientAPI.getPatients() if (response.success) { patients.value = response.data } diff --git a/frontend/src/renderer/src/views/Detection.vue b/frontend/src/renderer/src/views/Detection.vue index 885703d6..a99db0d8 100644 --- a/frontend/src/renderer/src/views/Detection.vue +++ b/frontend/src/renderer/src/views/Detection.vue @@ -142,13 +142,13 @@ - - - + + + - - - + + + @@ -289,7 +289,7 @@
视频
- + RTSP视频流 @@ -298,15 +298,9 @@