@@ -824,7 +824,7 @@
-
-
-
-
-
-
+
+
+
+
+
退出
{
if (response.ok) {
const result = await response.json()
if (result.success) {
- console.log('相机参数加载成功:', result.data)
+ console.log('设备参数加载成功:', result.data)
cameraForm.value = result.data
cameraDialogVisible.value = true
// console.log('相机参数加载成功:', patientInfo.value)
@@ -2441,8 +2462,8 @@ const getDevicesInit = async () => {
throw new Error(`HTTP ${response.status}: ${response.statusText}`)
}
} catch (error) {
- console.error('加载相机参数失败:', error)
- ElMessage.warning('加载相机参数失败,请检查网络连接')
+ console.error('加载设备参数失败:', error)
+ ElMessage.warning('加载设备参数失败,请检查网络连接')
}
}
@@ -3362,7 +3383,7 @@ function viewClick(e){
}
.pop-up-camera-container{
width: 668px;
- height:630px;
+ height:700px;
position: absolute;
top: 0;
right: 0;
From 75c3380ff37dbf5a107c9d855c4fcef988ac6ee4 Mon Sep 17 00:00:00 2001
From: root <13910913995@163.com>
Date: Sat, 7 Feb 2026 13:41:31 +0800
Subject: [PATCH 2/4] =?UTF-8?q?=E8=BF=9B=E5=85=A5=E6=A3=80=E6=B5=8B?=
=?UTF-8?q?=E9=A1=B5=E9=9D=A2=EF=BC=8C=E5=A2=9E=E5=8A=A0=E4=BA=86=E8=AE=BE?=
=?UTF-8?q?=E5=A4=87=E6=98=AF=E5=90=A6=E5=B0=B1=E7=BB=AA=E7=9A=84=E6=A3=80?=
=?UTF-8?q?=E6=B5=8B=E3=80=82?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
backend/config.ini | 4 +-
backend/devices/device_coordinator.py | 113 ++++++-
backend/devices/pressure_manager.py | 20 +-
backend/main.py | 44 ++-
frontend/src/renderer/src/views/Detection.vue | 293 +++++++++++++++++-
5 files changed, 440 insertions(+), 34 deletions(-)
diff --git a/backend/config.ini b/backend/config.ini
index 125af762..40992f17 100644
--- a/backend/config.ini
+++ b/backend/config.ini
@@ -30,7 +30,7 @@ backend = directshow
[CAMERA2]
enable = True
-device_index = 1
+device_index = 2
width = 1280
height = 720
fps = 30
@@ -60,7 +60,7 @@ pressure_port = COM3
pressure_baudrate = 115200
[REMOTE]
-enable = True
+enable = False
port = COM6
baudrate = 115200
timeout = 0.1
diff --git a/backend/devices/device_coordinator.py b/backend/devices/device_coordinator.py
index 7c569fb4..cb720318 100644
--- a/backend/devices/device_coordinator.py
+++ b/backend/devices/device_coordinator.py
@@ -57,6 +57,10 @@ class DeviceCoordinator:
self.is_initialized = False
self.is_running = False
self.coordinator_lock = threading.RLock()
+ self._init_summary = {
+ 'initialized_at': None,
+ 'device_results': {},
+ }
# 监控线程
self.monitor_thread = None
@@ -116,18 +120,22 @@ class DeviceCoordinator:
self._register_namespaces()
# 初始化设备(失败则降级继续)
- if not self._initialize_devices():
- self.logger.warning("设备初始化失败,将以降级模式继续运行")
-
+ init_ok = bool(self._initialize_devices())
+ self._init_summary['initialized_at'] = time.time()
+ if not init_ok:
+ self.logger.warning("设备初始化失败(没有任何设备初始化成功)")
+ self.is_initialized = False
+ return False
+
self.is_initialized = True
self.stats['start_time'] = time.time()
-
+
# 启动监控线程
self._start_monitor()
-
+
self.logger.info("设备协调器初始化成功")
self._emit_event('coordinator_initialized', {'devices': list(self.devices.keys())})
-
+
return True
except Exception as e:
@@ -195,12 +203,14 @@ class DeviceCoordinator:
try:
timeout_s = 45 if device_name == 'imu' else 30
result = future.result(timeout=timeout_s)
+ self._init_summary['device_results'][device_name] = bool(result)
if result:
success_count += 1
self.logger.info(f"{device_name}设备初始化成功")
else:
self.logger.error(f"{device_name}设备初始化失败")
except Exception as e:
+ self._init_summary['device_results'][device_name] = False
self.logger.error(f"{device_name}设备初始化异常: {e}")
# 至少需要一个设备初始化成功
@@ -214,6 +224,97 @@ class DeviceCoordinator:
except Exception as e:
self.logger.error(f"设备初始化失败: {e}")
return False
+
+ def get_enabled_devices(self) -> List[str]:
+ enabled = []
+ try:
+ for name, cfg in (self.device_configs or {}).items():
+ if isinstance(cfg, dict) and cfg.get('enable', False):
+ enabled.append(name)
+ except Exception:
+ pass
+ return enabled
+
+ def get_required_devices_for_detection(self) -> List[str]:
+ enabled = self.get_enabled_devices()
+ required = [d for d in enabled if d not in ('remote',)]
+ return required
+
+ def get_device_readiness(self, device_name: str) -> Dict[str, Any]:
+ enabled = bool(self.device_configs.get(device_name, {}).get('enable', False))
+ device = self.devices.get(device_name)
+ readiness = {
+ 'device_name': device_name,
+ 'enabled': enabled,
+ 'exists': device is not None,
+ 'initializing': False,
+ 'is_connected': False,
+ 'is_streaming': False,
+ 'ready': False,
+ }
+
+ if not device:
+ return readiness
+ status = None
+ try:
+ if hasattr(device, 'get_status'):
+ status = device.get_status()
+ except Exception:
+ status = None
+
+ try:
+ readiness['initializing'] = bool(getattr(device, '_initializing', False))
+ except Exception:
+ readiness['initializing'] = False
+ try:
+ if isinstance(status, dict) and 'is_connected' in status:
+ readiness['is_connected'] = bool(status.get('is_connected'))
+ else:
+ readiness['is_connected'] = bool(getattr(device, 'is_connected', False))
+ except Exception:
+ readiness['is_connected'] = False
+ try:
+ if isinstance(status, dict) and 'is_streaming' in status:
+ readiness['is_streaming'] = bool(status.get('is_streaming'))
+ else:
+ readiness['is_streaming'] = bool(getattr(device, 'is_streaming', False))
+ except Exception:
+ readiness['is_streaming'] = False
+
+ ok = readiness['is_connected'] and (not readiness['initializing'])
+ readiness['ready'] = bool(ok)
+ return readiness
+
+ def get_readiness_snapshot(self, required_devices: Optional[List[str]] = None) -> Dict[str, Any]:
+ required = required_devices if required_devices is not None else self.get_required_devices_for_detection()
+ devices = {}
+ for name in required:
+ devices[name] = self.get_device_readiness(name)
+
+ all_ready = bool(self.is_initialized) and all(devices[name].get('ready', False) for name in devices)
+ return {
+ 'coordinator': {
+ 'is_initialized': bool(self.is_initialized),
+ 'is_running': bool(self.is_running),
+ 'enabled_devices': self.get_enabled_devices(),
+ 'required_devices': required,
+ 'init_summary': self._init_summary,
+ },
+ 'devices': devices,
+ 'all_ready': all_ready,
+ }
+
+ def wait_until_ready_for_detection(self, timeout_s: float = 10.0, poll_interval_s: float = 0.2) -> Dict[str, Any]:
+ deadline = time.time() + max(0.0, float(timeout_s))
+ last_snapshot = self.get_readiness_snapshot()
+ while time.time() < deadline:
+ last_snapshot = self.get_readiness_snapshot()
+ if last_snapshot.get('all_ready', False):
+ return last_snapshot
+ time.sleep(max(0.05, float(poll_interval_s)))
+ last_snapshot['timeout'] = True
+ last_snapshot['timeout_s'] = float(timeout_s)
+ return last_snapshot
def _init_camera_by_name(self, device_name: str, section: str = 'CAMERA1') -> bool:
"""
diff --git a/backend/devices/pressure_manager.py b/backend/devices/pressure_manager.py
index 78c8b3a8..1d81f4d8 100644
--- a/backend/devices/pressure_manager.py
+++ b/backend/devices/pressure_manager.py
@@ -704,6 +704,7 @@ class PressureManager(BaseDevice):
Returns:
bool: 初始化是否成功
"""
+ self._initializing = True
try:
self.logger.info(f"正在初始化压力板设备...")
@@ -716,13 +717,28 @@ class PressureManager(BaseDevice):
else:
self.device = MockPressureDevice()
+ connected = False
+ try:
+ if self.use_mock:
+ connected = True
+ elif hasattr(self.device, 'is_connected'):
+ connected = bool(self.device.is_connected)
+ else:
+ connected = bool(self.check_hardware_connection())
+ except Exception:
+ connected = False
+
# 使用set_connected方法启动连接监控线程
- self.set_connected(True)
+ self.set_connected(bool(connected))
self._device_info.update({
'device_type': 'mock' if self.use_mock else 'real',
'matrix_size': '4x4' if hasattr(self.device, 'rows') else 'unknown'
})
+ if not connected:
+ self.logger.warning("压力板初始化完成但硬件未连接")
+ return False
+
self.logger.info(f"压力板初始化成功 - use_mock: {self.use_mock}")
return True
@@ -732,6 +748,8 @@ class PressureManager(BaseDevice):
self.set_connected(False)
self.device = None
return False
+ finally:
+ self._initializing = False
def start_streaming(self) -> bool:
diff --git a/backend/main.py b/backend/main.py
index cb1ba4ba..fc1a3e73 100644
--- a/backend/main.py
+++ b/backend/main.py
@@ -1293,22 +1293,38 @@ class AppServer:
try:
if not self.db_manager or not self.device_coordinator:
return jsonify({'success': False, 'error': '数据库管理器或设备管理器未初始化'}), 500
-
- # 检查设备是否已初始化
- if self.device_coordinator and not self.device_coordinator.is_initialized:
- self.logger.info('设备尚未初始化,等待初始化完成...')
- # 最多等待10秒
- start_wait = time.time()
- while not self.device_coordinator.is_initialized:
- if time.time() - start_wait > 10:
- return jsonify({'success': False, 'error': '设备初始化超时,请稍后重试'}), 503
- time.sleep(0.5)
- self.logger.info('设备初始化完成,继续开始检测')
- data = flask_request.get_json()
+ data = flask_request.get_json() or {}
patient_id = data.get('patient_id')
- creator_id = data.get('creator_id')
+ creator_id = data.get('creator_id')
+ force_start = bool(data.get('force_start', False))
+ if self.device_coordinator:
+ if not getattr(self.device_coordinator, 'is_initialized', False):
+ try:
+ threading.Thread(target=self._initialize_devices, daemon=True).start()
+ except Exception:
+ pass
+
+ readiness = {}
+ if not force_start:
+ try:
+ readiness = self.device_coordinator.wait_until_ready_for_detection(timeout_s=10.0, poll_interval_s=0.2)
+ except Exception as e:
+ self.logger.error(f'等待设备就绪失败: {e}')
+ readiness = {}
+
+ if not readiness or not readiness.get('all_ready', False):
+ return jsonify({
+ 'success': False,
+ 'error': '设备未就绪,请稍后重试',
+ 'readiness': readiness
+ }), 503
+ else:
+ try:
+ readiness = self.device_coordinator.get_readiness_snapshot()
+ except Exception:
+ readiness = {}
if not patient_id or not creator_id:
return jsonify({'success': False, 'error': '缺少患者ID或创建人ID'}), 400
@@ -1324,7 +1340,7 @@ class AppServer:
except Exception as monitor_error:
self.logger.error(f'启动设备连接监控失败: {monitor_error}')
- return jsonify({'success': True, 'session_id': session_id})
+ return jsonify({'success': True, 'session_id': session_id, 'forced': bool(force_start), 'readiness': readiness})
except Exception as e:
self.logger.error(f'开始检测失败: {e}')
return jsonify({'success': False, 'error': str(e)}), 500
diff --git a/frontend/src/renderer/src/views/Detection.vue b/frontend/src/renderer/src/views/Detection.vue
index 48052cc8..d11c95af 100644
--- a/frontend/src/renderer/src/views/Detection.vue
+++ b/frontend/src/renderer/src/views/Detection.vue
@@ -778,6 +778,37 @@
+
+
+
+
+
{{ initLoadingText }}
+
+
+
设备未就绪
+
{{ initErrorText || '请检查设备连接与配置后重试' }}
+
+
+
+
{{ getDeviceDisplayName(item.device_name) }}
+
{{ getNotReadyReason(item) }}
+
+
+
是否启用: {{ item.enabled === false ? 'N' : 'Y' }}
+
是否创建实例: {{ item.exists ? 'Y' : 'N' }}
+
是否初始化中: {{ item.initializing ? 'Y' : 'N' }}
+
是否已连接: {{ item.is_connected ? 'Y' : 'N' }}
+
+
+
+
+
+ 返回
+ 进入检测
+
+
+
+