This commit is contained in:
limengnan 2026-01-09 18:13:14 +08:00
commit a08f666306
7 changed files with 103 additions and 48 deletions

View File

@ -20,7 +20,7 @@ path = D:/BodyCheck/file/
[CAMERA1] [CAMERA1]
enabled = True enabled = True
device_index = 1 device_index = 0
width = 1280 width = 1280
height = 720 height = 720
fps = 30 fps = 30
@ -29,7 +29,7 @@ fourcc = MJPG
backend = directshow backend = directshow
[CAMERA2] [CAMERA2]
enabled = True enabled = False
device_index = 3 device_index = 3
width = 1280 width = 1280
height = 720 height = 720
@ -39,7 +39,7 @@ fourcc = MJPG
backend = directshow backend = directshow
[FEMTOBOLT] [FEMTOBOLT]
enabled = True enabled = False
algorithm_type = plt algorithm_type = plt
color_resolution = 1080P color_resolution = 1080P
depth_mode = NFOV_2X2BINNED depth_mode = NFOV_2X2BINNED
@ -50,22 +50,22 @@ fps = 15
synchronized_images_only = False synchronized_images_only = False
[DEVICES] [DEVICES]
imu_enabled = True imu_enabled = False
imu_device_type = ble imu_device_type = ble
imu_port = COM9 imu_port = COM9
imu_mac_address = ef:3c:1a:0a:fe:02 imu_mac_address = ef:3c:1a:0a:fe:02
imu_baudrate = 9600 imu_baudrate = 9600
pressure_enabled = True pressure_enabled = False
pressure_device_type = real pressure_device_type = real
pressure_use_mock = False pressure_use_mock = False
pressure_port = COM5 pressure_port = COM5
pressure_baudrate = 115200 pressure_baudrate = 115200
[REMOTE] [REMOTE]
enable = False
port = COM6 port = COM6
baudrate = 115200 baudrate = 115200
timeout = 0.1 timeout = 0.1
enable = True
strict_crc = False strict_crc = False
[SYSTEM] [SYSTEM]

View File

@ -232,7 +232,7 @@ class DatabaseManager:
treatment_info TEXT, -- 处理信息 treatment_info TEXT, -- 处理信息
remark_info TEXT, -- 备注信息 remark_info TEXT, -- 备注信息
detection_report TEXT, -- 生成检测报告的存储路径 detection_report TEXT, -- 生成检测报告的存储路径
status TEXT DEFAULT 'checking', -- 会话状态checking/checked/diagnosed/reported) status TEXT DEFAULT 'checking', -- 会话状态checking/checked/completed/reported)
data_ids TEXT, -- 关联的检测数据ID逗号分隔 data_ids TEXT, -- 关联的检测数据ID逗号分隔
created_at TIMESTAMP, -- 记录创建时间 created_at TIMESTAMP, -- 记录创建时间
FOREIGN KEY (patient_id) REFERENCES patients (id), -- 患者表外键约束 FOREIGN KEY (patient_id) REFERENCES patients (id), -- 患者表外键约束
@ -663,23 +663,28 @@ class DatabaseManager:
# 构造更新语句 # 构造更新语句
update_fields = [ update_fields = [
'duration = ?', 'duration = ?',
'end_time = ?', 'end_time = ?'
'status = ?'
] ]
update_values = [duration_seconds, now_str, 'checked'] update_values = [duration_seconds, now_str]
if diagnosis_info is not None: if diagnosis_info is not None:
update_fields.append('diagnosis_info = ?') update_fields.append('diagnosis_info = ?')
update_values.append(diagnosis_info) update_values.append(diagnosis_info)
if treatment_info is not None:
update_fields.append('treatment_info = ?')
update_values.append(treatment_info)
if suggestion_info is not None: if suggestion_info is not None:
update_fields.append('suggestion_info = ?') update_fields.append('suggestion_info = ?')
update_values.append(suggestion_info) update_values.append(suggestion_info)
status='checked' #默认状态为checked已完成检查
if treatment_info is not None: #处理信息不为空时状态设为completed已诊断处理
update_fields.append('treatment_info = ?')
update_values.append(treatment_info)
status='completed'
update_fields.append('status = ?')
update_values.append(status)
# 添加会话ID到参数列表 # 添加会话ID到参数列表
update_values.append(session_id) update_values.append(session_id)
@ -688,9 +693,9 @@ class DatabaseManager:
# 同步更新患者表的updated_at时间 # 同步更新患者表的updated_at时间
cursor.execute('''UPDATE patients SET updated_at = ? WHERE id = ?''', (now_str, patient_id)) cursor.execute('''UPDATE patients SET updated_at = ? WHERE id = ?''', (now_str, patient_id))
self._sync_patient_medical_history_from_session(cursor, session_id)
conn.commit() conn.commit()
logger.info(f'结束检测并更新会话: {session_id}, duration={duration_seconds}s, status=checked') logger.info(f'结束检测并更新会话: {session_id}, duration={duration_seconds}s, status={status}')
return True return True
except Exception as e: except Exception as e:
@ -699,7 +704,7 @@ class DatabaseManager:
return False return False
def update_session_all_info(self, session_id: str, diagnosis_info: str = None, treatment_info: str = None, suggestion_info: str = None, status: str = None): def update_session_all_info(self, session_id: str, diagnosis_info: str = None, treatment_info: str = None, suggestion_info: str = None):
"""同时更新会话的诊断信息、处理信息、建议信息和状态""" """同时更新会话的诊断信息、处理信息、建议信息和状态"""
conn = self.get_connection() conn = self.get_connection()
cursor = conn.cursor() cursor = conn.cursor()
@ -712,19 +717,16 @@ class DatabaseManager:
if diagnosis_info is not None: if diagnosis_info is not None:
update_fields.append('diagnosis_info = ?') update_fields.append('diagnosis_info = ?')
update_values.append(diagnosis_info) update_values.append(diagnosis_info)
status='checked' #默认状态为checked已完成检查
if treatment_info is not None: if treatment_info is not None:
update_fields.append('treatment_info = ?') update_fields.append('treatment_info = ?')
update_values.append(treatment_info) update_values.append(treatment_info)
status='completed' #处理信息不为空时状态设为completed已诊断处理
if suggestion_info is not None: if suggestion_info is not None:
update_fields.append('suggestion_info = ?') update_fields.append('suggestion_info = ?')
update_values.append(suggestion_info) update_values.append(suggestion_info)
if status is not None:
update_fields.append('status = ?')
update_values.append(status)
if not update_fields: if not update_fields:
logger.warning(f'没有提供要更新的信息: {session_id}') logger.warning(f'没有提供要更新的信息: {session_id}')
return return
@ -807,7 +809,7 @@ class DatabaseManager:
SELECT s.id, s.status, s.start_time, u.name as creator_name,s.detection_report as detection_report,s.data_ids as data_ids SELECT s.id, s.status, s.start_time, u.name as creator_name,s.detection_report as detection_report,s.data_ids as data_ids
FROM detection_sessions s FROM detection_sessions s
LEFT JOIN users u ON s.creator_id = u.id LEFT JOIN users u ON s.creator_id = u.id
WHERE s.patient_id = ? WHERE s.patient_id = ? and s.status in ('checked','completed','reported')
ORDER BY s.start_time DESC ORDER BY s.start_time DESC
LIMIT ? OFFSET ? LIMIT ? OFFSET ?
''', (patient_id, size, offset)) ''', (patient_id, size, offset))
@ -846,7 +848,7 @@ class DatabaseManager:
conn = self.get_connection() conn = self.get_connection()
cursor = conn.cursor() cursor = conn.cursor()
try: try:
cursor.execute('SELECT COUNT(*) FROM detection_sessions WHERE patient_id = ?', (patient_id,)) cursor.execute("SELECT COUNT(*) FROM detection_sessions WHERE status in ('checked','completed','reported') and patient_id = ?", (patient_id,))
row = cursor.fetchone() row = cursor.fetchone()
return int(row[0]) if row else 0 return int(row[0]) if row else 0
except Exception as e: except Exception as e:

View File

@ -246,10 +246,7 @@ class BaseDevice(ABC):
Dict[str, Any]: 设备信息 Dict[str, Any]: 设备信息
""" """
with self._lock: with self._lock:
return self._device_info.copy() return self._device_info.copy()
def _set_error(self, error_msg: str): def _set_error(self, error_msg: str):

View File

@ -165,9 +165,9 @@ class DeviceCoordinator:
# 普通相机初始化两个实例camera1 与 camera2 # 普通相机初始化两个实例camera1 与 camera2
# camera1 使用 [CAMERA1] 配置camera2 使用 [CAMERA2](若不存在则回退为 device_index+1 # camera1 使用 [CAMERA1] 配置camera2 使用 [CAMERA2](若不存在则回退为 device_index+1
if self.device_configs.get('camera1', {}).get('enabled', True): if self.device_configs.get('camera1', {}).get('enabled', False):
futures.append(('camera1', self.executor.submit(self._init_camera_by_name, 'camera1', 'CAMERA1'))) futures.append(('camera1', self.executor.submit(self._init_camera_by_name, 'camera1', 'CAMERA1')))
if self.device_configs.get('camera2', {}).get('enabled', True): if self.device_configs.get('camera2', {}).get('enabled', False):
futures.append(('camera2', self.executor.submit(self._init_camera_by_name, 'camera2', 'CAMERA2'))) futures.append(('camera2', self.executor.submit(self._init_camera_by_name, 'camera2', 'CAMERA2')))
# IMU传感器 # IMU传感器

View File

@ -163,6 +163,8 @@ class ConfigManager:
config = self._get_imu_config() config = self._get_imu_config()
elif device_name == 'pressure': elif device_name == 'pressure':
config = self._get_pressure_config() config = self._get_pressure_config()
elif device_name == 'remote':
config = self._get_remote_config()
else: else:
self.logger.warning(f"未知设备类型: {device_name}") self.logger.warning(f"未知设备类型: {device_name}")
@ -255,6 +257,21 @@ class ConfigManager:
'calibration_samples': self.config.getint('DEVICES', 'pressure_calibration_samples', fallback=50) 'calibration_samples': self.config.getint('DEVICES', 'pressure_calibration_samples', fallback=50)
} }
def _get_remote_config(self) -> Dict[str, Any]:
"""
获取远程控制配置
Returns:
Dict[str, Any]: 远程控制配置
"""
return {
'enabled': self.config.getboolean('REMOTE', 'enable', fallback=True),
'port': self.config.get('REMOTE', 'port', fallback='COM6'),
'baudrate': self.config.getint('REMOTE', 'baudrate', fallback=115200),
'timeout': self.config.getfloat('REMOTE', 'timeout', fallback=0.1),
'strict_crc': self.config.getboolean('REMOTE', 'strict_crc', fallback=False)
}
def get_system_config(self) -> Dict[str, Any]: def get_system_config(self) -> Dict[str, Any]:
""" """
获取系统配置 获取系统配置
@ -614,13 +631,7 @@ class ConfigManager:
'camera1': self.get_device_config('camera1'), 'camera1': self.get_device_config('camera1'),
'camera2': self.get_device_config('camera2'), 'camera2': self.get_device_config('camera2'),
'femtobolt': self.get_device_config('femtobolt'), 'femtobolt': self.get_device_config('femtobolt'),
'remote': { 'remote': self.get_device_config('remote')
'enabled': self.config.getboolean('DEVICES', 'remote_enabled', fallback=True),
'port': self.config.get('REMOTE', 'port', fallback='COM6'),
'baudrate': self.config.getint('REMOTE', 'baudrate', fallback=115200),
'timeout': self.config.getfloat('REMOTE', 'timeout', fallback=0.1),
'strict_crc': self.config.getboolean('REMOTE', 'strict_crc', fallback=False)
}
} }
def _batch_update_device_configs(self, configs: Dict[str, Dict[str, Any]]) -> Dict[str, Any]: def _batch_update_device_configs(self, configs: Dict[str, Dict[str, Any]]) -> Dict[str, Any]:
@ -787,6 +798,33 @@ class ConfigManager:
errors.append(f"FemtoBolt: {error_msg}") errors.append(f"FemtoBolt: {error_msg}")
self.logger.error(error_msg) self.logger.error(error_msg)
# Remote配置
if 'remote' in configs:
try:
config_data = configs['remote']
if 'enabled' in config_data:
self.set_config_value('REMOTE', 'enable', str(config_data['enabled']))
if 'port' in config_data:
self.set_config_value('REMOTE', 'port', config_data['port'])
if 'baudrate' in config_data:
self.set_config_value('REMOTE', 'baudrate', str(config_data['baudrate']))
if 'timeout' in config_data:
self.set_config_value('REMOTE', 'timeout', str(config_data['timeout']))
if 'strict_crc' in config_data:
self.set_config_value('REMOTE', 'strict_crc', str(config_data['strict_crc']))
results['remote'] = {
'success': True,
'message': '遥控器配置更新成功',
'config': config_data
}
self.logger.info(f"遥控器配置已更新: {config_data}")
except Exception as e:
error_msg = f'设置遥控器配置失败: {str(e)}'
results['remote'] = {'success': False, 'message': error_msg}
errors.append(f"Remote: {error_msg}")
self.logger.error(error_msg)
# 一次性保存所有配置 # 一次性保存所有配置
if results: # 只有在有配置更新时才保存 if results: # 只有在有配置更新时才保存
self.save_config() self.save_config()

View File

@ -246,8 +246,6 @@ class AppServer:
# 初始化录制管理器 # 初始化录制管理器
self.logger.info('正在初始化录制管理器...') self.logger.info('正在初始化录制管理器...')
camera1_manager = self.device_managers.get('camera1')
camera2_manager = self.device_managers.get('camera2')
femtobolt_manager = self.device_managers.get('femtobolt') femtobolt_manager = self.device_managers.get('femtobolt')
pressure_manager = self.device_managers.get('pressure') pressure_manager = self.device_managers.get('pressure')
@ -1159,6 +1157,22 @@ class AppServer:
except Exception as e: except Exception as e:
self.logger.error(f'获取设备状态失败: {e}') self.logger.error(f'获取设备状态失败: {e}')
return jsonify({'success': False, 'error': str(e)}), 500 return jsonify({'success': False, 'error': str(e)}), 500
@self.app.route('/api/cameras/check', methods=['GET'])
def check_cameras():
"""检查相机可用状态"""
try:
if not self.config_manager:
return jsonify({'success': False, 'error': '配置管理器未初始化'}), 500
results = CameraManager.check_cameras_status(self.config_manager)
return jsonify({
'success': True,
'data': results
})
except Exception as e:
self.logger.error(f"检查相机状态失败: {e}")
return jsonify({'success': False, 'error': str(e)}), 500
# ==================== 设备配置API ==================== # ==================== 设备配置API ====================
@ -1479,13 +1493,13 @@ class AppServer:
diagnosis_info = data.get('diagnosis_info') diagnosis_info = data.get('diagnosis_info')
treatment_info = data.get('treatment_info') treatment_info = data.get('treatment_info')
suggestion_info = data.get('suggestion_info') suggestion_info = data.get('suggestion_info')
status = data.get('status')
# 验证至少提供一个要更新的字段 # 验证至少提供一个要更新的字段
if not any([diagnosis_info, treatment_info, suggestion_info, status]): if not any([diagnosis_info, treatment_info, suggestion_info]):
return jsonify({ return jsonify({
'success': False, 'success': False,
'error': '至少需要提供一个要更新的字段diagnosis_info, treatment_info, suggestion_info, status' 'error': '至少需要提供一个要更新的字段diagnosis_info, treatment_info, suggestion_info'
}), 400 }), 400
# 调用数据库管理器的批量更新方法 # 调用数据库管理器的批量更新方法
@ -1493,8 +1507,7 @@ class AppServer:
session_id=session_id, session_id=session_id,
diagnosis_info=diagnosis_info, diagnosis_info=diagnosis_info,
treatment_info=treatment_info, treatment_info=treatment_info,
suggestion_info=suggestion_info, suggestion_info=suggestion_info
status=status
) )
# 构建更新信息反馈 # 构建更新信息反馈

View File

@ -1115,6 +1115,7 @@ const cameraStatus = computed(() => (camera1Status.value === '已连接' || came
const femtoboltStatus = ref('未连接') // (FemtoBolt) const femtoboltStatus = ref('未连接') // (FemtoBolt)
const imuStatus = ref('未连接') // IMU const imuStatus = ref('未连接') // IMU
const pressureStatus = ref('未连接') // const pressureStatus = ref('未连接') //
const remoteStatus = ref('未连接') //
// videoStatuscameraStatus // videoStatuscameraStatus
const videoStatus = computed(() => cameraStatus.value) const videoStatus = computed(() => cameraStatus.value)
@ -1507,6 +1508,10 @@ function connectWebSocket() {
pressureStatus.value = statusText pressureStatus.value = statusText
console.log(`⚖️ 压力传感器状态: ${statusText}`) console.log(`⚖️ 压力传感器状态: ${statusText}`)
break break
case 'remote':
remoteStatus.value = statusText
console.log(`📡 遥控器状态: ${statusText}`)
break
default: default:
console.warn('⚠️ 未知设备类型:', device_type) console.warn('⚠️ 未知设备类型:', device_type)
} }