Merge branch 'dev-v15' of http://121.37.111.42:3000/ThbTech/BodyBalanceEvaluation into dev-v15
This commit is contained in:
commit
a08f666306
@ -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]
|
||||||
|
|||||||
@ -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:
|
||||||
|
|||||||
@ -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):
|
||||||
|
|||||||
@ -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传感器
|
||||||
|
|||||||
@ -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()
|
||||||
|
|||||||
@ -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
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# 构建更新信息反馈
|
# 构建更新信息反馈
|
||||||
|
|||||||
@ -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('未连接') // 遥控器设备状态
|
||||||
|
|
||||||
// 为了向后兼容,保留videoStatus但映射到cameraStatus
|
// 为了向后兼容,保留videoStatus但映射到cameraStatus
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user