修改了配置及相关bug
This commit is contained in:
parent
93e45aec19
commit
9f2ecf02c4
@ -1,15 +0,0 @@
|
|||||||
{
|
|
||||||
"product": "BodyBalanceEvaluation",
|
|
||||||
"version": "1.5.0",
|
|
||||||
"machine_id": "W10-F5AC32003C0A160B",
|
|
||||||
"platform": "Windows",
|
|
||||||
"request_time": "2026-01-09T02:40:10.695573+00:00",
|
|
||||||
"hardware_info": {
|
|
||||||
"system": "Windows",
|
|
||||||
"machine": "AMD64",
|
|
||||||
"processor": "Intel64 Family 6 Model 165 Stepping 3, GenuineIntel",
|
|
||||||
"node": "PS2020LTDYIFOO"
|
|
||||||
},
|
|
||||||
"company_name": "北京天宏博科技有限公司",
|
|
||||||
"contact_info": "thb@163.com"
|
|
||||||
}
|
|
||||||
@ -19,7 +19,7 @@ max_backups = 7
|
|||||||
path = D:/BodyCheck/file/
|
path = D:/BodyCheck/file/
|
||||||
|
|
||||||
[CAMERA1]
|
[CAMERA1]
|
||||||
enabled = True
|
enable = True
|
||||||
device_index = 0
|
device_index = 0
|
||||||
width = 1280
|
width = 1280
|
||||||
height = 720
|
height = 720
|
||||||
@ -29,8 +29,8 @@ fourcc = MJPG
|
|||||||
backend = directshow
|
backend = directshow
|
||||||
|
|
||||||
[CAMERA2]
|
[CAMERA2]
|
||||||
enabled = False
|
enable = True
|
||||||
device_index = 3
|
device_index = 1
|
||||||
width = 1280
|
width = 1280
|
||||||
height = 720
|
height = 720
|
||||||
fps = 30
|
fps = 30
|
||||||
@ -39,7 +39,7 @@ fourcc = MJPG
|
|||||||
backend = directshow
|
backend = directshow
|
||||||
|
|
||||||
[FEMTOBOLT]
|
[FEMTOBOLT]
|
||||||
enabled = False
|
enable = True
|
||||||
algorithm_type = plt
|
algorithm_type = plt
|
||||||
color_resolution = 1080P
|
color_resolution = 1080P
|
||||||
depth_mode = NFOV_2X2BINNED
|
depth_mode = NFOV_2X2BINNED
|
||||||
@ -50,19 +50,19 @@ fps = 15
|
|||||||
synchronized_images_only = False
|
synchronized_images_only = False
|
||||||
|
|
||||||
[DEVICES]
|
[DEVICES]
|
||||||
imu_enabled = False
|
imu_enable = 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 = False
|
pressure_enable = 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
|
enable = True
|
||||||
port = COM6
|
port = COM6
|
||||||
baudrate = 115200
|
baudrate = 115200
|
||||||
timeout = 0.1
|
timeout = 0.1
|
||||||
@ -97,20 +97,12 @@ grace_days = 7
|
|||||||
dev_mode = False
|
dev_mode = False
|
||||||
|
|
||||||
[SCREEN_RECORDING]
|
[SCREEN_RECORDING]
|
||||||
# 录屏策略:ffmpeg(外部进程录制)或 threaded(内部线程录制)
|
|
||||||
strategy = ffmpeg
|
strategy = ffmpeg
|
||||||
# ffmpeg可执行文件绝对路径(Windows示例:D:/BodyCheck/ffmpeg/bin/ffmpeg.exe)
|
|
||||||
ffmpeg_path = D:/BodyCheck/ffmpeg/bin/ffmpeg.exe
|
ffmpeg_path = D:/BodyCheck/ffmpeg/bin/ffmpeg.exe
|
||||||
# 编码器:libx264(CPU)或 h264_nvenc(GPU,CPU占用更低,需显卡支持)
|
|
||||||
ffmpeg_codec = libx264
|
ffmpeg_codec = libx264
|
||||||
# 编码预设:ultrafast(CPU更低、文件更大);NVENC用 p1/p2 更快
|
|
||||||
ffmpeg_preset = ultrafast
|
ffmpeg_preset = ultrafast
|
||||||
# 编码线程数:限制CPU占用,按机器性能调整
|
|
||||||
ffmpeg_threads = 2
|
ffmpeg_threads = 2
|
||||||
# B帧数量:0可降低编码复杂度与CPU占用
|
|
||||||
ffmpeg_bframes = 0
|
ffmpeg_bframes = 0
|
||||||
# 关键帧间隔(GOP,单位:帧):数值越大CPU越低,seek精度下降
|
|
||||||
ffmpeg_gop = 50
|
ffmpeg_gop = 50
|
||||||
# 是否录制鼠标:0关闭,1开启
|
|
||||||
ffmpeg_draw_mouse = 0
|
ffmpeg_draw_mouse = 0
|
||||||
|
|
||||||
|
|||||||
@ -621,89 +621,6 @@ class DatabaseManager:
|
|||||||
logger.error(f'更新会话状态失败: {e}')
|
logger.error(f'更新会话状态失败: {e}')
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def update_session_endcheck(self, session_id: str, diagnosis_info: Optional[str] = None,
|
|
||||||
treatment_info: Optional[str] = None,
|
|
||||||
suggestion_info: Optional[str] = None) -> bool:
|
|
||||||
"""结束检测:根据 start_time 与当前时间计算持续时长并写入结束信息
|
|
||||||
|
|
||||||
行为:
|
|
||||||
- 计算并保存 `duration`
|
|
||||||
- 保存 `end_time` 为当前中国时区时间
|
|
||||||
- 可选更新 `diagnosis_info`、`treatment_info`、`suggestion_info`
|
|
||||||
- 设置 `status = 'checked'`
|
|
||||||
- 同步更新患者 `updated_at`
|
|
||||||
"""
|
|
||||||
conn = self.get_connection()
|
|
||||||
cursor = conn.cursor()
|
|
||||||
|
|
||||||
try:
|
|
||||||
# 读取会话的开始时间与患者ID
|
|
||||||
cursor.execute('SELECT start_time, patient_id FROM detection_sessions WHERE id = ?', (session_id,))
|
|
||||||
row = cursor.fetchone()
|
|
||||||
if not row:
|
|
||||||
logger.error(f'会话不存在: {session_id}')
|
|
||||||
return False
|
|
||||||
|
|
||||||
start_time_str, patient_id = row
|
|
||||||
if not start_time_str:
|
|
||||||
logger.error(f'会话缺少开始时间: {session_id}')
|
|
||||||
return False
|
|
||||||
|
|
||||||
# 计算持续时间(秒)
|
|
||||||
now_str = self.get_china_time()
|
|
||||||
try:
|
|
||||||
start_dt = datetime.strptime(start_time_str, '%Y-%m-%d %H:%M:%S')
|
|
||||||
now_dt = datetime.strptime(now_str, '%Y-%m-%d %H:%M:%S')
|
|
||||||
duration_seconds = max(0, int((now_dt - start_dt).total_seconds()))
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f'解析时间失败: start_time={start_time_str}, now={now_str}, error={e}')
|
|
||||||
return False
|
|
||||||
|
|
||||||
# 构造更新语句
|
|
||||||
update_fields = [
|
|
||||||
'duration = ?',
|
|
||||||
'end_time = ?'
|
|
||||||
|
|
||||||
]
|
|
||||||
update_values = [duration_seconds, now_str]
|
|
||||||
|
|
||||||
if diagnosis_info is not None:
|
|
||||||
update_fields.append('diagnosis_info = ?')
|
|
||||||
update_values.append(diagnosis_info)
|
|
||||||
|
|
||||||
if suggestion_info is not None:
|
|
||||||
update_fields.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到参数列表
|
|
||||||
update_values.append(session_id)
|
|
||||||
|
|
||||||
sql = f'''UPDATE detection_sessions SET {', '.join(update_fields)} WHERE id = ?'''
|
|
||||||
cursor.execute(sql, update_values)
|
|
||||||
|
|
||||||
# 同步更新患者表的updated_at时间
|
|
||||||
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()
|
|
||||||
logger.info(f'结束检测并更新会话: {session_id}, duration={duration_seconds}s, status={status}')
|
|
||||||
return True
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
conn.rollback()
|
|
||||||
logger.error(f'结束检测更新失败: {e}')
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def update_session_all_info(self, session_id: str, diagnosis_info: str = None, treatment_info: str = None, suggestion_info: 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()
|
||||||
@ -714,19 +631,22 @@ class DatabaseManager:
|
|||||||
update_fields = []
|
update_fields = []
|
||||||
update_values = []
|
update_values = []
|
||||||
|
|
||||||
if diagnosis_info is not None:
|
if diagnosis_info is not None and diagnosis_info.strip() != '':
|
||||||
update_fields.append('diagnosis_info = ?')
|
update_fields.append('diagnosis_info = ?')
|
||||||
update_values.append(diagnosis_info)
|
update_values.append(diagnosis_info)
|
||||||
status='checked' #默认状态为checked:已完成检查
|
status='checked' #默认状态为checked:已完成检查
|
||||||
if treatment_info is not None:
|
if treatment_info is not None and treatment_info.strip() != '':
|
||||||
update_fields.append('treatment_info = ?')
|
update_fields.append('treatment_info = ?')
|
||||||
update_values.append(treatment_info)
|
update_values.append(treatment_info)
|
||||||
status='completed' #处理信息不为空时,状态设为completed:已诊断处理
|
status='completed' #处理信息不为空时,状态设为completed:已诊断处理
|
||||||
|
|
||||||
if suggestion_info is not None:
|
if suggestion_info is not None and suggestion_info.strip() != '':
|
||||||
update_fields.append('suggestion_info = ?')
|
update_fields.append('suggestion_info = ?')
|
||||||
update_values.append(suggestion_info)
|
update_values.append(suggestion_info)
|
||||||
|
|
||||||
|
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
|
||||||
@ -754,11 +674,11 @@ class DatabaseManager:
|
|||||||
updated_info.append(f'状态({status})')
|
updated_info.append(f'状态({status})')
|
||||||
|
|
||||||
logger.info(f'批量更新会话信息成功: {session_id}, 更新字段: {", ".join(updated_info)}')
|
logger.info(f'批量更新会话信息成功: {session_id}, 更新字段: {", ".join(updated_info)}')
|
||||||
|
return True
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
conn.rollback()
|
conn.rollback()
|
||||||
logger.error(f'批量更新会话信息失败: {e}')
|
logger.error(f'批量更新会话信息失败: {e}')
|
||||||
raise
|
return False
|
||||||
|
|
||||||
def _sync_patient_medical_history_from_session(self, cursor, session_id: str) -> None:
|
def _sync_patient_medical_history_from_session(self, cursor, session_id: str) -> None:
|
||||||
"""根据会话信息同步患者 medical_history 的 doctor/status/lastcheck_time 字段"""
|
"""根据会话信息同步患者 medical_history 的 doctor/status/lastcheck_time 字段"""
|
||||||
@ -806,7 +726,8 @@ class DatabaseManager:
|
|||||||
try:
|
try:
|
||||||
offset = (page - 1) * size
|
offset = (page - 1) * size
|
||||||
cursor.execute('''
|
cursor.execute('''
|
||||||
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,
|
||||||
|
(SELECT COUNT(*) FROM detection_data WHERE session_id = s.id) as data_count
|
||||||
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 = ? and s.status in ('checked','completed','reported')
|
WHERE s.patient_id = ? and s.status in ('checked','completed','reported')
|
||||||
@ -827,7 +748,8 @@ class DatabaseManager:
|
|||||||
'start_time': r[2],
|
'start_time': r[2],
|
||||||
'creator_name': r[3],
|
'creator_name': r[3],
|
||||||
'detection_report': r[4],
|
'detection_report': r[4],
|
||||||
'data_ids': r[5]
|
'data_ids': r[5],
|
||||||
|
'data_count': r[6]
|
||||||
}
|
}
|
||||||
sessions.append({
|
sessions.append({
|
||||||
'id': item.get('id'),
|
'id': item.get('id'),
|
||||||
@ -835,7 +757,8 @@ class DatabaseManager:
|
|||||||
'start_time': item.get('start_time'),
|
'start_time': item.get('start_time'),
|
||||||
'creator_name': item.get('creator_name'),
|
'creator_name': item.get('creator_name'),
|
||||||
'detection_report': item.get('detection_report'),
|
'detection_report': item.get('detection_report'),
|
||||||
'data_ids': item.get('data_ids')
|
'data_ids': item.get('data_ids'),
|
||||||
|
'data_count': item.get('data_count', 0)
|
||||||
})
|
})
|
||||||
return sessions
|
return sessions
|
||||||
|
|
||||||
@ -1118,15 +1041,22 @@ class DatabaseManager:
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
def has_session_detection_data(self, session_id: str) -> bool:
|
def has_session_detection_data(self, session_id: str) -> bool:
|
||||||
"""检查指定会话是否存在检测数据,用于判断单次检测是否有效"""
|
"""检查指定会话是否存在检测数据或视频数据,用于判断单次检测是否有效"""
|
||||||
conn = self.get_connection()
|
conn = self.get_connection()
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
try:
|
try:
|
||||||
|
# 检查检测数据
|
||||||
cursor.execute('SELECT COUNT(1) FROM detection_data WHERE session_id = ?', (session_id,))
|
cursor.execute('SELECT COUNT(1) FROM detection_data WHERE session_id = ?', (session_id,))
|
||||||
row = cursor.fetchone()
|
row = cursor.fetchone()
|
||||||
count = row[0] if row else 0
|
data_count = row[0] if row else 0
|
||||||
exists = count > 0
|
|
||||||
logger.info(f'会话 {session_id} 检测数据存在: {exists} (count={count})')
|
# 检查视频数据
|
||||||
|
cursor.execute('SELECT COUNT(1) FROM detection_video WHERE session_id = ?', (session_id,))
|
||||||
|
video_row = cursor.fetchone()
|
||||||
|
video_count = video_row[0] if video_row else 0
|
||||||
|
|
||||||
|
exists = (data_count > 0) or (video_count > 0)
|
||||||
|
logger.info(f'会话 {session_id} 数据检查: data_count={data_count}, video_count={video_count}, exists={exists}')
|
||||||
return exists
|
return exists
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f'检查会话检测数据存在失败: {e}')
|
logger.error(f'检查会话检测数据存在失败: {e}')
|
||||||
|
|||||||
@ -159,29 +159,29 @@ class DeviceCoordinator:
|
|||||||
futures = []
|
futures = []
|
||||||
|
|
||||||
# FemtoBolt深度相机
|
# FemtoBolt深度相机
|
||||||
if self.device_configs.get('femtobolt', {}).get('enabled', False):
|
if self.device_configs.get('femtobolt', {}).get('enable', False):
|
||||||
future = self.executor.submit(self._init_femtobolt)
|
future = self.executor.submit(self._init_femtobolt)
|
||||||
futures.append(('femtobolt', future))
|
futures.append(('femtobolt', future))
|
||||||
|
|
||||||
# 普通相机:初始化两个实例(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', False):
|
if self.device_configs.get('camera1', {}).get('enable', 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', False):
|
if self.device_configs.get('camera2', {}).get('enable', 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传感器
|
||||||
if self.device_configs.get('imu', {}).get('enabled', False):
|
if self.device_configs.get('imu', {}).get('enable', False):
|
||||||
future = self.executor.submit(self._init_imu)
|
future = self.executor.submit(self._init_imu)
|
||||||
futures.append(('imu', future))
|
futures.append(('imu', future))
|
||||||
|
|
||||||
# 压力传感器
|
# 压力传感器
|
||||||
if self.device_configs.get('pressure', {}).get('enabled', False):
|
if self.device_configs.get('pressure', {}).get('enable', False):
|
||||||
future = self.executor.submit(self._init_pressure)
|
future = self.executor.submit(self._init_pressure)
|
||||||
futures.append(('pressure', future))
|
futures.append(('pressure', future))
|
||||||
|
|
||||||
# 遥控器
|
# 遥控器
|
||||||
if self.device_configs.get('remote', {}).get('enabled', False):
|
if self.device_configs.get('remote', {}).get('enable', False):
|
||||||
future = self.executor.submit(self._init_remote)
|
future = self.executor.submit(self._init_remote)
|
||||||
futures.append(('remote', future))
|
futures.append(('remote', future))
|
||||||
|
|
||||||
@ -244,8 +244,8 @@ class DeviceCoordinator:
|
|||||||
return parser.getboolean(sec, key)
|
return parser.getboolean(sec, key)
|
||||||
except Exception:
|
except Exception:
|
||||||
return fallback
|
return fallback
|
||||||
enabled = get_bool(section, 'enabled', True)
|
enable = get_bool(section, 'enable', True)
|
||||||
if not enabled:
|
if not enable:
|
||||||
self.logger.info(f"{device_name} 未启用,跳过初始化")
|
self.logger.info(f"{device_name} 未启用,跳过初始化")
|
||||||
return False
|
return False
|
||||||
# 填充覆盖项
|
# 填充覆盖项
|
||||||
@ -682,8 +682,8 @@ class DeviceCoordinator:
|
|||||||
return parser.getboolean(sec, key)
|
return parser.getboolean(sec, key)
|
||||||
except Exception:
|
except Exception:
|
||||||
return fallback
|
return fallback
|
||||||
enabled = get_bool(section, 'enabled', True)
|
enable = get_bool(section, 'enable', True)
|
||||||
if not enabled:
|
if not enable:
|
||||||
raise Exception(f"{device_name} 未启用")
|
raise Exception(f"{device_name} 未启用")
|
||||||
idx2 = get_int(section, 'device_index', None)
|
idx2 = get_int(section, 'device_index', None)
|
||||||
if idx2 is not None:
|
if idx2 is not None:
|
||||||
|
|||||||
@ -39,7 +39,7 @@ class RemoteControlManager(BaseDevice):
|
|||||||
timeout = float(self.config_manager.get_config_value('REMOTE', 'timeout', fallback='0.1'))
|
timeout = float(self.config_manager.get_config_value('REMOTE', 'timeout', fallback='0.1'))
|
||||||
|
|
||||||
instance_config: Dict[str, Any] = {
|
instance_config: Dict[str, Any] = {
|
||||||
'enabled': True,
|
'enable': True,
|
||||||
'port': port,
|
'port': port,
|
||||||
'baudrate': baudrate,
|
'baudrate': baudrate,
|
||||||
'timeout': timeout,
|
'timeout': timeout,
|
||||||
|
|||||||
@ -1280,7 +1280,7 @@ class RecordingManager:
|
|||||||
'body_pose': None,
|
'body_pose': None,
|
||||||
'body_image': None,
|
'body_image': None,
|
||||||
'foot_data': detection_data.get('foot_data'),
|
'foot_data': detection_data.get('foot_data'),
|
||||||
'foot_data_image': None,
|
'foot_data_image': detection_data.get('foot_data_image'),
|
||||||
'foot1_image': None,
|
'foot1_image': None,
|
||||||
'foot2_image': None,
|
'foot2_image': None,
|
||||||
'screen_image': None,
|
'screen_image': None,
|
||||||
@ -1292,8 +1292,7 @@ class RecordingManager:
|
|||||||
image_fields = [
|
image_fields = [
|
||||||
('body_image', 'body'),
|
('body_image', 'body'),
|
||||||
('foot1_image', 'foot1'),
|
('foot1_image', 'foot1'),
|
||||||
('foot2_image', 'foot2'),
|
('foot2_image', 'foot2')
|
||||||
('foot_data_image', 'foot_data')
|
|
||||||
]
|
]
|
||||||
|
|
||||||
for field, prefix in image_fields:
|
for field, prefix in image_fields:
|
||||||
@ -1322,10 +1321,14 @@ class RecordingManager:
|
|||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.logger.error(f'保存{field}失败: {e}')
|
self.logger.error(f'保存{field}失败: {e}')
|
||||||
# 屏幕截图
|
# 完整屏幕截图--根据screen_location 进行截图
|
||||||
screen_image = self._capture_screen_image(data_dir, data.get('screen_location'), timestamp=timestamp)
|
screen_image = self._capture_screen_image(data_dir, data.get('screen_location'),'screen', timestamp=timestamp)
|
||||||
if screen_image:
|
if screen_image:
|
||||||
data['screen_image'] = str(os.path.join( patient_id, session_id, f"image_{timestamp}", screen_image))
|
data['screen_image'] = str(os.path.join( patient_id, session_id, f"image_{timestamp}", screen_image))
|
||||||
|
# 足部压力屏幕截图——根据foot_data_image 进行截图
|
||||||
|
foot_data_image = self._capture_screen_image(data_dir, data.get('foot_data_image'),'foot_data', timestamp=timestamp)
|
||||||
|
if foot_data_image:
|
||||||
|
data['foot_data_image'] = str(os.path.join( patient_id, session_id, f"image_{timestamp}", foot_data_image))
|
||||||
|
|
||||||
self.logger.debug(f'数据保存完成: {session_id}, 时间戳: {timestamp}')
|
self.logger.debug(f'数据保存完成: {session_id}, 时间戳: {timestamp}')
|
||||||
|
|
||||||
@ -1336,7 +1339,7 @@ class RecordingManager:
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
def _capture_screen_image(self, data_dir, screen_location, timestamp) -> Optional[str]:
|
def _capture_screen_image(self, data_dir, screen_location,type, timestamp) -> Optional[str]:
|
||||||
"""
|
"""
|
||||||
采集屏幕截图,根据screen_region 进行截图
|
采集屏幕截图,根据screen_region 进行截图
|
||||||
|
|
||||||
@ -1358,7 +1361,7 @@ class RecordingManager:
|
|||||||
|
|
||||||
# 保存截图
|
# 保存截图
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
screen_filename = f'screen_{timestamp}.jpg'
|
screen_filename = f'{type}_{timestamp}.jpg'
|
||||||
image_path = Path(data_dir) / screen_filename
|
image_path = Path(data_dir) / screen_filename
|
||||||
screenshot.save(str(image_path), quality=95, optimize=True)
|
screenshot.save(str(image_path), quality=95, optimize=True)
|
||||||
|
|
||||||
|
|||||||
@ -143,7 +143,7 @@ class ConfigManager:
|
|||||||
获取设备配置
|
获取设备配置
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
device_name: 设备名称 (camera1, camera2, femtobolt, imu, pressure)
|
device_name: 设备名称 (camera1, camera2, femtobolt, imu, pressure, remote)
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Dict[str, Any]: 设备配置字典
|
Dict[str, Any]: 设备配置字典
|
||||||
@ -180,7 +180,7 @@ class ConfigManager:
|
|||||||
Dict[str, Any]: 相机配置
|
Dict[str, Any]: 相机配置
|
||||||
"""
|
"""
|
||||||
return {
|
return {
|
||||||
'enabled': self.config.getboolean('CAMERA1', 'enabled', fallback=True),
|
'enable': self.config.getboolean('CAMERA1', 'enable', fallback=False),
|
||||||
'device_index': self.config.getint('CAMERA1', 'device_index', fallback=0),
|
'device_index': self.config.getint('CAMERA1', 'device_index', fallback=0),
|
||||||
'width': self.config.getint('CAMERA1', 'width', fallback=1280),
|
'width': self.config.getint('CAMERA1', 'width', fallback=1280),
|
||||||
'height': self.config.getint('CAMERA1', 'height', fallback=720),
|
'height': self.config.getint('CAMERA1', 'height', fallback=720),
|
||||||
@ -197,7 +197,7 @@ class ConfigManager:
|
|||||||
Dict[str, Any]:
|
Dict[str, Any]:
|
||||||
"""
|
"""
|
||||||
return {
|
return {
|
||||||
'enabled': self.config.getboolean('CAMERA2', 'enabled', fallback=True),
|
'enable': self.config.getboolean('CAMERA2', 'enable', fallback=False),
|
||||||
'device_index': self.config.getint('CAMERA2', 'device_index', fallback=0),
|
'device_index': self.config.getint('CAMERA2', 'device_index', fallback=0),
|
||||||
'width': self.config.getint('CAMERA2', 'width', fallback=1280),
|
'width': self.config.getint('CAMERA2', 'width', fallback=1280),
|
||||||
'height': self.config.getint('CAMERA2', 'height', fallback=720),
|
'height': self.config.getint('CAMERA2', 'height', fallback=720),
|
||||||
@ -214,7 +214,7 @@ class ConfigManager:
|
|||||||
Dict[str, Any]: FemtoBolt配置
|
Dict[str, Any]: FemtoBolt配置
|
||||||
"""
|
"""
|
||||||
return {
|
return {
|
||||||
'enabled': self.config.getboolean('FEMTOBOLT', 'enabled', fallback=True),
|
'enable': self.config.getboolean('FEMTOBOLT', 'enable', fallback=False),
|
||||||
'algorithm_type': self.config.get('FEMTOBOLT', 'algorithm_type', fallback='opencv'),
|
'algorithm_type': self.config.get('FEMTOBOLT', 'algorithm_type', fallback='opencv'),
|
||||||
'color_resolution': self.config.get('FEMTOBOLT', 'color_resolution', fallback='1080P'),
|
'color_resolution': self.config.get('FEMTOBOLT', 'color_resolution', fallback='1080P'),
|
||||||
'depth_mode': self.config.get('FEMTOBOLT', 'depth_mode', fallback='NFOV_UNBINNED'),
|
'depth_mode': self.config.get('FEMTOBOLT', 'depth_mode', fallback='NFOV_UNBINNED'),
|
||||||
@ -232,7 +232,7 @@ class ConfigManager:
|
|||||||
Dict[str, Any]: IMU配置
|
Dict[str, Any]: IMU配置
|
||||||
"""
|
"""
|
||||||
return {
|
return {
|
||||||
'enabled': self.config.getboolean('DEVICES', 'imu_enabled', fallback=True),
|
'enable': self.config.getboolean('DEVICES', 'imu_enable', fallback=False),
|
||||||
'device_type': self.config.get('DEVICES', 'imu_device_type', fallback='mock'),
|
'device_type': self.config.get('DEVICES', 'imu_device_type', fallback='mock'),
|
||||||
'port': self.config.get('DEVICES', 'imu_port', fallback='COM7'),
|
'port': self.config.get('DEVICES', 'imu_port', fallback='COM7'),
|
||||||
'baudrate': self.config.getint('DEVICES', 'imu_baudrate', fallback=9600),
|
'baudrate': self.config.getint('DEVICES', 'imu_baudrate', fallback=9600),
|
||||||
@ -249,7 +249,7 @@ class ConfigManager:
|
|||||||
Dict[str, Any]: 压力传感器配置
|
Dict[str, Any]: 压力传感器配置
|
||||||
"""
|
"""
|
||||||
return {
|
return {
|
||||||
'enabled': self.config.getboolean('DEVICES', 'pressure_enabled', fallback=True),
|
'enable': self.config.getboolean('DEVICES', 'pressure_enable', fallback=False),
|
||||||
'device_type': self.config.get('DEVICES', 'pressure_device_type', fallback='mock'),
|
'device_type': self.config.get('DEVICES', 'pressure_device_type', fallback='mock'),
|
||||||
'port': self.config.get('DEVICES', 'pressure_port', fallback='COM8'),
|
'port': self.config.get('DEVICES', 'pressure_port', fallback='COM8'),
|
||||||
'baudrate': self.config.getint('DEVICES', 'pressure_baudrate', fallback=115200),
|
'baudrate': self.config.getint('DEVICES', 'pressure_baudrate', fallback=115200),
|
||||||
@ -265,7 +265,7 @@ class ConfigManager:
|
|||||||
Dict[str, Any]: 远程控制配置
|
Dict[str, Any]: 远程控制配置
|
||||||
"""
|
"""
|
||||||
return {
|
return {
|
||||||
'enabled': self.config.getboolean('REMOTE', 'enable', fallback=True),
|
'enable': self.config.getboolean('REMOTE', 'enable', fallback=False),
|
||||||
'port': self.config.get('REMOTE', 'port', fallback='COM6'),
|
'port': self.config.get('REMOTE', 'port', fallback='COM6'),
|
||||||
'baudrate': self.config.getint('REMOTE', 'baudrate', fallback=115200),
|
'baudrate': self.config.getint('REMOTE', 'baudrate', fallback=115200),
|
||||||
'timeout': self.config.getfloat('REMOTE', 'timeout', fallback=0.1),
|
'timeout': self.config.getfloat('REMOTE', 'timeout', fallback=0.1),
|
||||||
@ -376,7 +376,7 @@ class ConfigManager:
|
|||||||
warnings = []
|
warnings = []
|
||||||
|
|
||||||
# 验证必需的配置段
|
# 验证必需的配置段
|
||||||
required_sections = ['DEVICES', 'CAMERA1', 'CAMERA2', 'FEMTOBOLT', 'SYSTEM']
|
required_sections = ['DEVICES', 'CAMERA1', 'CAMERA2', 'FEMTOBOLT', 'REMOTE']
|
||||||
for section in required_sections:
|
for section in required_sections:
|
||||||
if not self.config.has_section(section):
|
if not self.config.has_section(section):
|
||||||
errors.append(f"缺少必需的配置段: {section}")
|
errors.append(f"缺少必需的配置段: {section}")
|
||||||
@ -395,228 +395,7 @@ class ConfigManager:
|
|||||||
'valid': len(errors) == 0
|
'valid': len(errors) == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
# HTTP接口设备参数设置方法
|
|
||||||
def set_imu_config(self, config_data: Dict[str, Any]) -> Dict[str, Any]:
|
|
||||||
"""
|
|
||||||
设置IMU设备配置
|
|
||||||
|
|
||||||
Args:
|
|
||||||
config_data: IMU配置数据
|
|
||||||
{
|
|
||||||
'device_type': 'real' | 'mock' | 'ble',
|
|
||||||
'port': 'COM6',
|
|
||||||
'baudrate': 9600,
|
|
||||||
'mac_address': 'ef:3c:1a:0a:fe:02'
|
|
||||||
}
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Dict[str, Any]: 设置结果
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
# 验证必需参数
|
|
||||||
if 'device_type' in config_data:
|
|
||||||
self.set_config_value('DEVICES', 'imu_device_type', config_data['device_type'])
|
|
||||||
if 'port' in config_data:
|
|
||||||
self.set_config_value('DEVICES', 'imu_port', config_data['port'])
|
|
||||||
if 'baudrate' in config_data:
|
|
||||||
self.set_config_value('DEVICES', 'imu_baudrate', str(config_data['baudrate']))
|
|
||||||
if 'mac_address' in config_data:
|
|
||||||
self.set_config_value('DEVICES', 'imu_mac_address', config_data['mac_address'])
|
|
||||||
|
|
||||||
# 保存配置
|
|
||||||
self.save_config()
|
|
||||||
|
|
||||||
self.logger.info(f"IMU配置已更新: {config_data}")
|
|
||||||
return {
|
|
||||||
'success': True,
|
|
||||||
'message': 'IMU配置更新成功',
|
|
||||||
'config': self.get_device_config('imu')
|
|
||||||
}
|
|
||||||
except Exception as e:
|
|
||||||
self.logger.error(f"设置IMU配置失败: {e}")
|
|
||||||
return {
|
|
||||||
'success': False,
|
|
||||||
'message': f'设置IMU配置失败: {str(e)}'
|
|
||||||
}
|
|
||||||
|
|
||||||
def set_pressure_config(self, config_data: Dict[str, Any]) -> Dict[str, Any]:
|
|
||||||
"""
|
|
||||||
设置压力板设备配置
|
|
||||||
|
|
||||||
Args:
|
|
||||||
config_data: 压力板配置数据
|
|
||||||
{
|
|
||||||
'device_type': 'real' | 'mock',
|
|
||||||
'use_mock': False,
|
|
||||||
'port': 'COM5',
|
|
||||||
'baudrate': 115200
|
|
||||||
}
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Dict[str, Any]: 设置结果
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
# 验证必需参数
|
|
||||||
if 'device_type' in config_data:
|
|
||||||
self.set_config_value('DEVICES', 'pressure_device_type', config_data['device_type'])
|
|
||||||
if 'use_mock' in config_data:
|
|
||||||
self.set_config_value('DEVICES', 'pressure_use_mock', str(config_data['use_mock']))
|
|
||||||
if 'port' in config_data:
|
|
||||||
self.set_config_value('DEVICES', 'pressure_port', config_data['port'])
|
|
||||||
if 'baudrate' in config_data:
|
|
||||||
self.set_config_value('DEVICES', 'pressure_baudrate', str(config_data['baudrate']))
|
|
||||||
|
|
||||||
# 保存配置
|
|
||||||
self.save_config()
|
|
||||||
|
|
||||||
self.logger.info(f"压力板配置已更新: {config_data}")
|
|
||||||
return {
|
|
||||||
'success': True,
|
|
||||||
'message': '压力板配置更新成功',
|
|
||||||
'config': self.get_device_config('pressure')
|
|
||||||
}
|
|
||||||
except Exception as e:
|
|
||||||
self.logger.error(f"设置压力板配置失败: {e}")
|
|
||||||
return {
|
|
||||||
'success': False,
|
|
||||||
'message': f'设置压力板配置失败: {str(e)}'
|
|
||||||
}
|
|
||||||
|
|
||||||
def set_camera1_config(self, config_data: Dict[str, Any]) -> Dict[str, Any]:
|
|
||||||
"""
|
|
||||||
设置相机设备配置
|
|
||||||
|
|
||||||
Args:
|
|
||||||
config_data: 相机配置数据
|
|
||||||
{
|
|
||||||
'device_index': 1,
|
|
||||||
'width': 1280,
|
|
||||||
'height': 720,
|
|
||||||
'fps': 30
|
|
||||||
}
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Dict[str, Any]: 设置结果
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
# 验证必需参数
|
|
||||||
if 'device_index' in config_data:
|
|
||||||
self.set_config_value('CAMERA1', 'device_index', str(config_data['device_index']))
|
|
||||||
if 'width' in config_data:
|
|
||||||
self.set_config_value('CAMERA1', 'width', str(config_data['width']))
|
|
||||||
if 'height' in config_data:
|
|
||||||
self.set_config_value('CAMERA1', 'height', str(config_data['height']))
|
|
||||||
if 'fps' in config_data:
|
|
||||||
self.set_config_value('CAMERA1', 'fps', str(config_data['fps']))
|
|
||||||
if 'backend' in config_data:
|
|
||||||
self.set_config_value('CAMERA1', 'backend', str(config_data['backend']))
|
|
||||||
|
|
||||||
# 保存配置
|
|
||||||
self.save_config()
|
|
||||||
|
|
||||||
self.logger.info(f"相机配置已更新: {config_data}")
|
|
||||||
return {
|
|
||||||
'success': True,
|
|
||||||
'message': '相机配置更新成功',
|
|
||||||
'config': self.get_device_config('camera1')
|
|
||||||
}
|
|
||||||
except Exception as e:
|
|
||||||
self.logger.error(f"设置相机配置失败: {e}")
|
|
||||||
return {
|
|
||||||
'success': False,
|
|
||||||
'message': f'设置相机配置失败: {str(e)}'
|
|
||||||
}
|
|
||||||
def set_camera2_config(self, config_data: Dict[str, Any]) -> Dict[str, Any]:
|
|
||||||
"""
|
|
||||||
设置相机设备配置
|
|
||||||
|
|
||||||
Args:
|
|
||||||
config_data: 相机配置数据
|
|
||||||
{
|
|
||||||
'device_index': 1,
|
|
||||||
'width': 1280,
|
|
||||||
'height': 720,
|
|
||||||
'fps': 30
|
|
||||||
}
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Dict[str, Any]: 设置结果
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
# 验证必需参数
|
|
||||||
if 'device_index' in config_data:
|
|
||||||
self.set_config_value('CAMERA2', 'device_index', str(config_data['device_index']))
|
|
||||||
if 'width' in config_data:
|
|
||||||
self.set_config_value('CAMERA2', 'width', str(config_data['width']))
|
|
||||||
if 'height' in config_data:
|
|
||||||
self.set_config_value('CAMERA2', 'height', str(config_data['height']))
|
|
||||||
if 'fps' in config_data:
|
|
||||||
self.set_config_value('CAMERA2', 'fps', str(config_data['fps']))
|
|
||||||
if 'backend' in config_data:
|
|
||||||
self.set_config_value('CAMERA2', 'backend', str(config_data['backend']))
|
|
||||||
|
|
||||||
# 保存配置
|
|
||||||
self.save_config()
|
|
||||||
|
|
||||||
self.logger.info(f"相机配置已更新: {config_data}")
|
|
||||||
return {
|
|
||||||
'success': True,
|
|
||||||
'message': '相机配置更新成功',
|
|
||||||
'config': self.get_device_config('camera2')
|
|
||||||
}
|
|
||||||
except Exception as e:
|
|
||||||
self.logger.error(f"设置相机配置失败: {e}")
|
|
||||||
return {
|
|
||||||
'success': False,
|
|
||||||
'message': f'设置相机配置失败: {str(e)}'
|
|
||||||
}
|
|
||||||
def set_femtobolt_config(self, config_data: Dict[str, Any]) -> Dict[str, Any]:
|
|
||||||
"""
|
|
||||||
设置FemtoBolt设备配置
|
|
||||||
|
|
||||||
Args:
|
|
||||||
config_data: FemtoBolt配置数据
|
|
||||||
{
|
|
||||||
'color_resolution': '1080P',
|
|
||||||
'depth_mode': 'NFOV_UNBINNED',
|
|
||||||
'fps': 30,
|
|
||||||
'depth_range_min': 1200,
|
|
||||||
'depth_range_max': 1500
|
|
||||||
}
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Dict[str, Any]: 设置结果
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
# 验证必需参数
|
|
||||||
if 'algorithm_type' in config_data:
|
|
||||||
self.set_config_value('FEMTOBOLT', 'algorithm_type', config_data['algorithm_type'])
|
|
||||||
if 'color_resolution' in config_data:
|
|
||||||
self.set_config_value('FEMTOBOLT', 'color_resolution', config_data['color_resolution'])
|
|
||||||
if 'depth_mode' in config_data:
|
|
||||||
self.set_config_value('FEMTOBOLT', 'depth_mode', config_data['depth_mode'])
|
|
||||||
if 'camera_fps' in config_data:
|
|
||||||
self.set_config_value('FEMTOBOLT', 'camera_fps', str(config_data['camera_fps']))
|
|
||||||
if 'depth_range_min' in config_data:
|
|
||||||
self.set_config_value('FEMTOBOLT', 'depth_range_min', str(config_data['depth_range_min']))
|
|
||||||
if 'depth_range_max' in config_data:
|
|
||||||
self.set_config_value('FEMTOBOLT', 'depth_range_max', str(config_data['depth_range_max']))
|
|
||||||
|
|
||||||
# 保存配置
|
|
||||||
self.save_config()
|
|
||||||
|
|
||||||
self.logger.info(f"FemtoBolt配置已更新: {config_data}")
|
|
||||||
return {
|
|
||||||
'success': True,
|
|
||||||
'message': 'FemtoBolt配置更新成功',
|
|
||||||
'config': self.get_device_config('femtobolt')
|
|
||||||
}
|
|
||||||
except Exception as e:
|
|
||||||
self.logger.error(f"设置FemtoBolt配置失败: {e}")
|
|
||||||
return {
|
|
||||||
'success': False,
|
|
||||||
'message': f'设置FemtoBolt配置失败: {str(e)}'
|
|
||||||
}
|
|
||||||
|
|
||||||
def get_all_device_configs(self) -> Dict[str, Any]:
|
def get_all_device_configs(self) -> Dict[str, Any]:
|
||||||
"""
|
"""
|
||||||
@ -652,6 +431,8 @@ class ConfigManager:
|
|||||||
if 'imu' in configs:
|
if 'imu' in configs:
|
||||||
try:
|
try:
|
||||||
config_data = configs['imu']
|
config_data = configs['imu']
|
||||||
|
if 'enable' in config_data:
|
||||||
|
self.set_config_value('DEVICES', 'imu_enable', str(config_data['enable']))
|
||||||
if 'device_type' in config_data:
|
if 'device_type' in config_data:
|
||||||
self.set_config_value('DEVICES', 'imu_device_type', config_data['device_type'])
|
self.set_config_value('DEVICES', 'imu_device_type', config_data['device_type'])
|
||||||
if 'use_mock' in config_data:
|
if 'use_mock' in config_data:
|
||||||
@ -677,6 +458,8 @@ class ConfigManager:
|
|||||||
if 'pressure' in configs:
|
if 'pressure' in configs:
|
||||||
try:
|
try:
|
||||||
config_data = configs['pressure']
|
config_data = configs['pressure']
|
||||||
|
if 'enable' in config_data:
|
||||||
|
self.set_config_value('DEVICES', 'pressure_enable', str(config_data['enable']))
|
||||||
if 'device_type' in config_data:
|
if 'device_type' in config_data:
|
||||||
self.set_config_value('DEVICES', 'pressure_device_type', config_data['device_type'])
|
self.set_config_value('DEVICES', 'pressure_device_type', config_data['device_type'])
|
||||||
if 'use_mock' in config_data:
|
if 'use_mock' in config_data:
|
||||||
@ -702,6 +485,8 @@ class ConfigManager:
|
|||||||
if 'camera1' in configs:
|
if 'camera1' in configs:
|
||||||
try:
|
try:
|
||||||
config_data = configs['camera1']
|
config_data = configs['camera1']
|
||||||
|
if 'enable' in config_data:
|
||||||
|
self.set_config_value('CAMERA1', 'enable', str(config_data['enable']))
|
||||||
if 'device_index' in config_data:
|
if 'device_index' in config_data:
|
||||||
self.set_config_value('CAMERA1', 'device_index', str(config_data['device_index']))
|
self.set_config_value('CAMERA1', 'device_index', str(config_data['device_index']))
|
||||||
if 'width' in config_data:
|
if 'width' in config_data:
|
||||||
@ -734,6 +519,8 @@ class ConfigManager:
|
|||||||
if 'camera2' in configs:
|
if 'camera2' in configs:
|
||||||
try:
|
try:
|
||||||
config_data = configs['camera2']
|
config_data = configs['camera2']
|
||||||
|
if 'enable' in config_data:
|
||||||
|
self.set_config_value('CAMERA2', 'enable', str(config_data['enable']))
|
||||||
if 'device_index' in config_data:
|
if 'device_index' in config_data:
|
||||||
self.set_config_value('CAMERA2', 'device_index', str(config_data['device_index']))
|
self.set_config_value('CAMERA2', 'device_index', str(config_data['device_index']))
|
||||||
if 'width' in config_data:
|
if 'width' in config_data:
|
||||||
@ -767,6 +554,8 @@ class ConfigManager:
|
|||||||
if 'femtobolt' in configs:
|
if 'femtobolt' in configs:
|
||||||
try:
|
try:
|
||||||
config_data = configs['femtobolt']
|
config_data = configs['femtobolt']
|
||||||
|
if 'enable' in config_data:
|
||||||
|
self.set_config_value('FEMTOBOLT', 'enable', str(config_data['enable']))
|
||||||
if 'algorithm_type' in config_data:
|
if 'algorithm_type' in config_data:
|
||||||
self.set_config_value('FEMTOBOLT', 'algorithm_type', config_data['algorithm_type'])
|
self.set_config_value('FEMTOBOLT', 'algorithm_type', config_data['algorithm_type'])
|
||||||
if 'color_resolution' in config_data:
|
if 'color_resolution' in config_data:
|
||||||
@ -802,8 +591,8 @@ class ConfigManager:
|
|||||||
if 'remote' in configs:
|
if 'remote' in configs:
|
||||||
try:
|
try:
|
||||||
config_data = configs['remote']
|
config_data = configs['remote']
|
||||||
if 'enabled' in config_data:
|
if 'enable' in config_data:
|
||||||
self.set_config_value('REMOTE', 'enable', str(config_data['enabled']))
|
self.set_config_value('REMOTE', 'enable', str(config_data['enable']))
|
||||||
if 'port' in config_data:
|
if 'port' in config_data:
|
||||||
self.set_config_value('REMOTE', 'port', config_data['port'])
|
self.set_config_value('REMOTE', 'port', config_data['port'])
|
||||||
if 'baudrate' in config_data:
|
if 'baudrate' in config_data:
|
||||||
|
|||||||
@ -1211,7 +1211,7 @@ class AppServer:
|
|||||||
}), 400
|
}), 400
|
||||||
|
|
||||||
# 验证数据格式
|
# 验证数据格式
|
||||||
supported_devices = ['camera1','camera2', 'femtobolt','imu','pressure']
|
supported_devices = ['camera1','camera2', 'femtobolt','imu','pressure','remote']
|
||||||
for device_name in data.keys():
|
for device_name in data.keys():
|
||||||
if device_name not in supported_devices:
|
if device_name not in supported_devices:
|
||||||
return jsonify({
|
return jsonify({
|
||||||
@ -1386,7 +1386,7 @@ 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')
|
||||||
success = self.db_manager.update_session_endcheck(
|
success = self.db_manager.update_session_all_info(
|
||||||
session_id,
|
session_id,
|
||||||
diagnosis_info=diagnosis_info,
|
diagnosis_info=diagnosis_info,
|
||||||
treatment_info=treatment_info,
|
treatment_info=treatment_info,
|
||||||
@ -1534,13 +1534,6 @@ class AppServer:
|
|||||||
suggestion_info = data.get('suggestion_info')
|
suggestion_info = data.get('suggestion_info')
|
||||||
|
|
||||||
|
|
||||||
# 验证至少提供一个要更新的字段
|
|
||||||
if not any([diagnosis_info, treatment_info, suggestion_info]):
|
|
||||||
return jsonify({
|
|
||||||
'success': False,
|
|
||||||
'error': '至少需要提供一个要更新的字段(diagnosis_info, treatment_info, suggestion_info)'
|
|
||||||
}), 400
|
|
||||||
|
|
||||||
# 调用数据库管理器的批量更新方法
|
# 调用数据库管理器的批量更新方法
|
||||||
self.db_manager.update_session_all_info(
|
self.db_manager.update_session_all_info(
|
||||||
session_id=session_id,
|
session_id=session_id,
|
||||||
@ -1557,8 +1550,6 @@ class AppServer:
|
|||||||
updated_fields.append('处理信息')
|
updated_fields.append('处理信息')
|
||||||
if suggestion_info is not None:
|
if suggestion_info is not None:
|
||||||
updated_fields.append('建议信息')
|
updated_fields.append('建议信息')
|
||||||
if status is not None:
|
|
||||||
updated_fields.append(f'状态({status})')
|
|
||||||
|
|
||||||
self.logger.info(f'会话信息保存成功: {session_id}, 更新字段: {", ".join(updated_fields)}')
|
self.logger.info(f'会话信息保存成功: {session_id}, 更新字段: {", ".join(updated_fields)}')
|
||||||
|
|
||||||
|
|||||||
@ -10,7 +10,7 @@
|
|||||||
- [REMOTE] port,缺省 COM6
|
- [REMOTE] port,缺省 COM6
|
||||||
- [REMOTE] baudrate,缺省 115200
|
- [REMOTE] baudrate,缺省 115200
|
||||||
- [REMOTE] timeout,缺省 0.1 秒
|
- [REMOTE] timeout,缺省 0.1 秒
|
||||||
- [DEVICES] remote_enabled(是否启用),缺省 true
|
- [DEVICES] remote_enable(是否启用),缺省 true
|
||||||
- 串口参数:115200 bps,8 数据位,1 停止位,无校验(8N1)。
|
- 串口参数:115200 bps,8 数据位,1 停止位,无校验(8N1)。
|
||||||
|
|
||||||
## 报文格式
|
## 报文格式
|
||||||
|
|||||||
@ -17,14 +17,13 @@
|
|||||||
<el-button type="primary" class="endbutton" @click="endClick">结束检测</el-button>
|
<el-button type="primary" class="endbutton" @click="endClick">结束检测</el-button>
|
||||||
</div>
|
</div>
|
||||||
<div class="displayleft">
|
<div class="displayleft">
|
||||||
<div class="icon-box" @click="isPhotoAlbum = true" title="图片相册">
|
|
||||||
<img src="@/assets/detection/photoalbum.svg" alt="">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="icon-box" title="截图" @click="saveDetectionData">
|
<div class="icon-box" title="截图" @click="saveDetectionData">
|
||||||
<img src="@/assets/detection/screenshot.png" alt="">
|
<img src="@/assets/detection/screenshot.png" alt="">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="icon-box" @click="isPhotoAlbum = true" title="相册">
|
||||||
|
<img src="@/assets/detection/photoalbum.svg" alt="">
|
||||||
|
</div>
|
||||||
|
|
||||||
<div v-if="!isStartVideo" class="icon-box" @click="startVideoClick" title="开始录像">
|
<div v-if="!isStartVideo" class="icon-box" @click="startVideoClick" title="开始录像">
|
||||||
<img src="@/assets/detection/startvideo.png" alt="">
|
<img src="@/assets/detection/startvideo.png" alt="">
|
||||||
@ -712,8 +711,7 @@
|
|||||||
<div class="pop-up-tip-text" v-if="!isVideoOperation">本次检测未截图或录像操作,不予存档记录!</div>
|
<div class="pop-up-tip-text" v-if="!isVideoOperation">本次检测未截图或录像操作,不予存档记录!</div>
|
||||||
<div class="pop-up-tip-text" v-if="isVideoOperation">本次检测未截图操作,存档记录不可生成报告!</div>
|
<div class="pop-up-tip-text" v-if="isVideoOperation">本次检测未截图操作,存档记录不可生成报告!</div>
|
||||||
<div class="tipconfirmbutton-box">
|
<div class="tipconfirmbutton-box">
|
||||||
<el-button v-if="!isVideoOperation" type="primary" class="tipconfirmbutton" @click="closeTipClick">确定</el-button>
|
<el-button type="primary" class="tipconfirmbutton" @click="closeTipClick">确定</el-button>
|
||||||
<el-button v-if="isVideoOperation" type="primary" class="tipconfirmbutton" @click="isDiagnosticMessage = true">确定</el-button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -746,7 +744,7 @@
|
|||||||
<div style="margin: 0 10px;">至</div>
|
<div style="margin: 0 10px;">至</div>
|
||||||
<el-input v-model="cameraForm.femtobolt.depth_range_max" placeholder="请输入最大值"
|
<el-input v-model="cameraForm.femtobolt.depth_range_max" placeholder="请输入最大值"
|
||||||
style="width: 200px;"/>
|
style="width: 200px;"/>
|
||||||
<el-checkbox v-model="cameraForm.femtobolt.enabled" label="有效" size="large" style="width: 60px;margin-left:10px ;" />
|
<el-checkbox v-model="cameraForm.femtobolt.enable" label="有效" size="large" style="width: 60px;margin-left:10px ;" />
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="pop-up-camera-display" style="padding-top: 30px;padding-bottom: 10px;">
|
<div class="pop-up-camera-display" style="padding-top: 30px;padding-bottom: 10px;">
|
||||||
@ -757,27 +755,27 @@
|
|||||||
<div class="pop-up-camera-name">相机上</div>
|
<div class="pop-up-camera-name">相机上</div>
|
||||||
<el-radio-group v-model="cameraForm.camera1.device_index">
|
<el-radio-group v-model="cameraForm.camera1.device_index">
|
||||||
<div style="display: flex;justify-content: space-between;width: 435px;">
|
<div style="display: flex;justify-content: space-between;width: 435px;">
|
||||||
|
<el-radio :value="0" border>0号</el-radio>
|
||||||
<el-radio :value="1" border>1号</el-radio>
|
<el-radio :value="1" border>1号</el-radio>
|
||||||
<el-radio :value="2" border>2号</el-radio>
|
<el-radio :value="2" border>2号</el-radio>
|
||||||
<el-radio :value="3" border>3号</el-radio>
|
<el-radio :value="3" border>3号</el-radio>
|
||||||
<el-radio :value="4" border>4号</el-radio>
|
<el-radio :value="4" border>4号</el-radio>
|
||||||
<el-radio :value="5" border>5号</el-radio>
|
|
||||||
</div>
|
</div>
|
||||||
</el-radio-group>
|
</el-radio-group>
|
||||||
<el-checkbox v-model="cameraForm.camera1.enabled" label="有效" size="large" style="width: 60px;margin-left:10px ;" />
|
<el-checkbox v-model="cameraForm.camera1.enable" label="有效" size="large" style="width: 60px;margin-left:10px ;" />
|
||||||
</div>
|
</div>
|
||||||
<div class="pop-up-camera-display" style="padding-top: 20px;">
|
<div class="pop-up-camera-display" style="padding-top: 20px;">
|
||||||
<div class="pop-up-camera-name">相机下</div>
|
<div class="pop-up-camera-name">相机下</div>
|
||||||
<el-radio-group v-model="cameraForm.camera2.device_index">
|
<el-radio-group v-model="cameraForm.camera2.device_index">
|
||||||
<div style="display: flex;justify-content: space-between;width: 435px;">
|
<div style="display: flex;justify-content: space-between;width: 435px;">
|
||||||
|
<el-radio :value="0" border>0号</el-radio>
|
||||||
<el-radio :value="1" border>1号</el-radio>
|
<el-radio :value="1" border>1号</el-radio>
|
||||||
<el-radio :value="2" border>2号</el-radio>
|
<el-radio :value="2" border>2号</el-radio>
|
||||||
<el-radio :value="3" border>3号</el-radio>
|
<el-radio :value="3" border>3号</el-radio>
|
||||||
<el-radio :value="4" border>4号</el-radio>
|
<el-radio :value="4" border>4号</el-radio>
|
||||||
<el-radio :value="5" border>5号</el-radio>
|
|
||||||
</div>
|
</div>
|
||||||
</el-radio-group>
|
</el-radio-group>
|
||||||
<el-checkbox v-model="cameraForm.camera2.enabled" label="有效" size="large" style="width: 60px;margin-left:10px ;" />
|
<el-checkbox v-model="cameraForm.camera2.enable" label="有效" size="large" style="width: 60px;margin-left:10px ;" />
|
||||||
</div>
|
</div>
|
||||||
<div class="pop-up-camera-display" style="padding-top: 30px;padding-bottom: 00px;">
|
<div class="pop-up-camera-display" style="padding-top: 30px;padding-bottom: 00px;">
|
||||||
<div class="pop-up-camera-line"></div>
|
<div class="pop-up-camera-line"></div>
|
||||||
@ -788,7 +786,7 @@
|
|||||||
<el-select v-model="cameraForm.remote.port" placeholder="请选择" style="width: 434px;">
|
<el-select v-model="cameraForm.remote.port" placeholder="请选择" style="width: 434px;">
|
||||||
<el-option v-for="item in remotePortData" :label="item" :value="item" />
|
<el-option v-for="item in remotePortData" :label="item" :value="item" />
|
||||||
</el-select>
|
</el-select>
|
||||||
<el-checkbox v-model="cameraForm.remote.enabled" label="有效" size="large" style="width: 60px;margin-left:10px ;" />
|
<el-checkbox v-model="cameraForm.remote.enable" label="有效" size="large" style="width: 60px;margin-left:10px ;" />
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="form-actions-display">
|
<div class="form-actions-display">
|
||||||
@ -1017,7 +1015,7 @@ const cameraForm = ref({ // 相机参数
|
|||||||
},
|
},
|
||||||
remote:{
|
remote:{
|
||||||
port: '', // IMU串口号
|
port: '', // IMU串口号
|
||||||
enabled: false
|
enable: false
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
const calculatedAge = ref(null)
|
const calculatedAge = ref(null)
|
||||||
@ -1922,51 +1920,7 @@ function handlePressureData(data) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async function handleDiagnosticInfo(status) {
|
|
||||||
try {
|
|
||||||
// 检查是否有活跃的会话ID
|
|
||||||
if (!patientInfo.value.sessionId) {
|
|
||||||
throw new Error('缺少会话Id')
|
|
||||||
}
|
|
||||||
// 调用后端API采集检测数据
|
|
||||||
const response = await fetch(`${BACKEND_URL}/api/detection/${patientInfo.value.sessionId}/save-info`, {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json'
|
|
||||||
},
|
|
||||||
body: JSON.stringify({
|
|
||||||
diagnosis_info: diagnosticForm.diagnosis_info,
|
|
||||||
treatment_info: diagnosticForm.treatment_info,
|
|
||||||
suggestion_info: diagnosticForm.suggestion_info,
|
|
||||||
status: status,
|
|
||||||
session_id: patientInfo.value.sessionId,
|
|
||||||
})
|
|
||||||
})
|
|
||||||
if (!response.ok) {
|
|
||||||
throw new Error(`HTTP ${response.status}: ${response.statusText}`)
|
|
||||||
}
|
|
||||||
|
|
||||||
const result = await response.json()
|
|
||||||
if (result.success) {
|
|
||||||
// 显示成功消息
|
|
||||||
ElMessage.success({
|
|
||||||
message: status + '诊断信息成功',
|
|
||||||
duration: 5000
|
|
||||||
})
|
|
||||||
|
|
||||||
} else {
|
|
||||||
throw new Error(result.message || '诊断信息失败')
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
ElMessage.error({
|
|
||||||
message: errorMessage,
|
|
||||||
duration: 5000
|
|
||||||
})
|
|
||||||
|
|
||||||
} finally {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 保存检测数据
|
// 保存检测数据
|
||||||
async function saveDetectionData() {
|
async function saveDetectionData() {
|
||||||
@ -2216,10 +2170,6 @@ const loadPatientInfo = async () => {
|
|||||||
// 处理页面关闭或刷新事件
|
// 处理页面关闭或刷新事件
|
||||||
const handleBeforeUnload = (event) => {
|
const handleBeforeUnload = (event) => {
|
||||||
console.log('页面即将关闭,正在清理资源...')
|
console.log('页面即将关闭,正在清理资源...')
|
||||||
|
|
||||||
|
|
||||||
// 停止检测
|
|
||||||
stopDetection()
|
|
||||||
// 断开WebSocket连接
|
// 断开WebSocket连接
|
||||||
disconnectWebSocket()
|
disconnectWebSocket()
|
||||||
|
|
||||||
@ -2406,15 +2356,6 @@ onUnmounted(() => {
|
|||||||
console.log('✅ 定时器已清理')
|
console.log('✅ 定时器已清理')
|
||||||
}
|
}
|
||||||
|
|
||||||
// // 停止录制
|
|
||||||
// if (isRecording.value === true) {
|
|
||||||
// stopRecord()
|
|
||||||
// console.log('✅ 录制已停止')
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // 停止检测
|
|
||||||
// stopDetection()
|
|
||||||
|
|
||||||
// 断开WebSocket连接
|
// 断开WebSocket连接
|
||||||
disconnectWebSocket()
|
disconnectWebSocket()
|
||||||
|
|
||||||
@ -2576,6 +2517,8 @@ function refreshClick(type) {
|
|||||||
devicesSocket.emit('restart_device', { device_type: 'imu' })
|
devicesSocket.emit('restart_device', { device_type: 'imu' })
|
||||||
}else if(type == 'pressure'){
|
}else if(type == 'pressure'){
|
||||||
devicesSocket.emit('restart_device', { device_type: 'pressure' })
|
devicesSocket.emit('restart_device', { device_type: 'pressure' })
|
||||||
|
}else if(type == 'remote'){
|
||||||
|
devicesSocket.emit('restart_device', { device_type: 'remote' })
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
console.warn('⚠️ Socket服务未连接,无法重启设备!')
|
console.warn('⚠️ Socket服务未连接,无法重启设备!')
|
||||||
|
|||||||
@ -103,7 +103,27 @@
|
|||||||
<el-table-column prop="report" label="报告" width="60" align="center">
|
<el-table-column prop="report" label="报告" width="60" align="center">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<div
|
<div
|
||||||
v-if="scope.row.detection_report == null"
|
v-if="scope.row.data_count == 0"
|
||||||
|
style="width:28px;
|
||||||
|
font-family: 'Noto Sans SC';
|
||||||
|
font-weight: 400;
|
||||||
|
font-style: normal;
|
||||||
|
font-size: 14px;
|
||||||
|
color: rgba(255, 255, 255, 0.5);
|
||||||
|
line-height: 18px;
|
||||||
|
cursor: not-allowed;">无 数据</div>
|
||||||
|
<div
|
||||||
|
v-if="scope.row.data_count > 0 && scope.row.status == 'checked'"
|
||||||
|
style="width:28px;
|
||||||
|
font-family: 'Noto Sans SC';
|
||||||
|
font-weight: 400;
|
||||||
|
font-style: normal;
|
||||||
|
font-size: 14px;
|
||||||
|
color: rgba(255, 255, 255, 0.5);
|
||||||
|
line-height: 18px;
|
||||||
|
cursor: not-allowed;">未 诊断</div>
|
||||||
|
<div
|
||||||
|
v-else-if="scope.row.status == 'completed'"
|
||||||
style="width:28px;
|
style="width:28px;
|
||||||
font-family: 'Noto Sans SC';
|
font-family: 'Noto Sans SC';
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
@ -113,7 +133,7 @@
|
|||||||
line-height: 18px;
|
line-height: 18px;
|
||||||
cursor: pointer;"
|
cursor: pointer;"
|
||||||
@click.stop="generateReport(scope.row,scope.$index)">生成报告</div>
|
@click.stop="generateReport(scope.row,scope.$index)">生成报告</div>
|
||||||
<div class="patientprofile-file-box" v-if="scope.row.detection_report != null">
|
<div class="patientprofile-file-box" v-else-if="scope.row.status == 'reported'">
|
||||||
<img src="@/assets/new/file.png" alt="" @click.stop="fileClick(scope.row)">
|
<img src="@/assets/new/file.png" alt="" @click.stop="fileClick(scope.row)">
|
||||||
<img src="@/assets/new/del.png" class="patientprofile-del" alt=""
|
<img src="@/assets/new/del.png" class="patientprofile-del" alt=""
|
||||||
@click.stop="delPDFClick(scope.row)">
|
@click.stop="delPDFClick(scope.row)">
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user