Merge branch 'main' of http://121.37.111.42:3000/ThbTech/BodyBalanceEvaluation into main
This commit is contained in:
commit
c4e2b3e741
@ -14,8 +14,8 @@ a = Analysis(
|
||||
('dll/femtobolt/bin/ob_usb.dll', 'dll/femtobolt/bin'), # Orbbec USB库
|
||||
('dll/femtobolt/bin/live555.dll', 'dll/femtobolt/bin'), # Live555库
|
||||
('dll/femtobolt/bin/OrbbecSDKConfig_v1.0.xml', 'dll/femtobolt/bin'), # Orbbec配置文件 ('dll/smitsense/SMiTSenseUsb-F3.0.dll', 'dll/smitsense'), # SMiTSense传感器库
|
||||
('dll/smitsense/Wrapper.dll', 'dll/smitsense'), # Wrapper
|
||||
('dll/smitsense/SMiTSenseUsb-F3.0.dll', 'dll/smitsense'), # Wrapper
|
||||
('dll/smitsense/SMiTSenseUsb-F3.0.dll', 'dll/smitsense'), # SMiTSenseUsb库
|
||||
('dll/smitsense/Wrapper.dll', 'dll/smitsense'), # SMiTSense传感器库包装类
|
||||
],
|
||||
hiddenimports=[
|
||||
'flask',
|
||||
|
@ -42,8 +42,8 @@ a = Analysis(
|
||||
('dll/femtobolt/bin/ob_usb.dll', 'dll/femtobolt/bin'), # Orbbec USB库
|
||||
('dll/femtobolt/bin/live555.dll', 'dll/femtobolt/bin'), # Live555库
|
||||
('dll/femtobolt/bin/OrbbecSDKConfig_v1.0.xml', 'dll/femtobolt/bin'), # Orbbec配置文件 ('dll/smitsense/SMiTSenseUsb-F3.0.dll', 'dll/smitsense'), # SMiTSense传感器库
|
||||
('dll/smitsense/Wrapper.dll', 'dll/smitsense'), # Wrapper
|
||||
('dll/smitsense/SMiTSenseUsb-F3.0.dll', 'dll/smitsense'), # Wrapper
|
||||
('dll/smitsense/SMiTSenseUsb-F3.0.dll', 'dll/smitsense'), # SMiTSenseUsb库
|
||||
('dll/smitsense/Wrapper.dll', 'dll/smitsense'), # SMiTSense传感器库包装类
|
||||
],
|
||||
hiddenimports=[
|
||||
'flask',
|
||||
|
@ -1,242 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
设备配置HTTP API接口
|
||||
提供通过HTTP方式设置设备参数的功能
|
||||
"""
|
||||
|
||||
import json
|
||||
import logging
|
||||
import sys
|
||||
import os
|
||||
from flask import Flask, request, jsonify
|
||||
from typing import Dict, Any
|
||||
|
||||
# 添加路径以支持导入
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
from utils.config_manager import ConfigManager
|
||||
|
||||
|
||||
class ConfigAPI:
|
||||
"""配置API类"""
|
||||
|
||||
def __init__(self, app: Flask = None):
|
||||
"""
|
||||
初始化配置API
|
||||
|
||||
Args:
|
||||
app: Flask应用实例
|
||||
"""
|
||||
self.logger = logging.getLogger(f"{__name__}.ConfigAPI")
|
||||
self.config_manager = ConfigManager()
|
||||
|
||||
if app:
|
||||
self.init_app(app)
|
||||
|
||||
def init_app(self, app: Flask):
|
||||
"""
|
||||
初始化Flask应用
|
||||
|
||||
Args:
|
||||
app: Flask应用实例
|
||||
"""
|
||||
self.app = app
|
||||
self._register_routes()
|
||||
|
||||
def _register_routes(self):
|
||||
"""
|
||||
注册路由
|
||||
"""
|
||||
# 获取所有设备配置
|
||||
@self.app.route('/api/config/devices', methods=['GET'])
|
||||
def get_all_device_configs():
|
||||
"""获取所有设备配置"""
|
||||
try:
|
||||
configs = self.config_manager.get_all_device_configs()
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'data': configs
|
||||
})
|
||||
except Exception as e:
|
||||
self.logger.error(f"获取设备配置失败: {e}")
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'message': f'获取设备配置失败: {str(e)}'
|
||||
}), 500
|
||||
|
||||
# 获取单个设备配置
|
||||
@self.app.route('/api/config/devices/<device_name>', methods=['GET'])
|
||||
def get_device_config(device_name: str):
|
||||
"""获取单个设备配置"""
|
||||
try:
|
||||
if device_name not in ['imu', 'pressure', 'camera', 'femtobolt']:
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'message': f'不支持的设备类型: {device_name}'
|
||||
}), 400
|
||||
|
||||
config = self.config_manager.get_device_config(device_name)
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'data': config
|
||||
})
|
||||
except Exception as e:
|
||||
self.logger.error(f"获取{device_name}配置失败: {e}")
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'message': f'获取{device_name}配置失败: {str(e)}'
|
||||
}), 500
|
||||
|
||||
# 设置IMU配置
|
||||
@self.app.route('/api/config/devices/imu', methods=['POST'])
|
||||
def set_imu_config():
|
||||
"""设置IMU配置"""
|
||||
try:
|
||||
data = request.get_json()
|
||||
if not data:
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'message': '请求数据不能为空'
|
||||
}), 400
|
||||
|
||||
result = self.config_manager.set_imu_config(data)
|
||||
status_code = 200 if result['success'] else 400
|
||||
return jsonify(result), status_code
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f"设置IMU配置失败: {e}")
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'message': f'设置IMU配置失败: {str(e)}'
|
||||
}), 500
|
||||
|
||||
# 设置压力板配置
|
||||
@self.app.route('/api/config/devices/pressure', methods=['POST'])
|
||||
def set_pressure_config():
|
||||
"""设置压力板配置"""
|
||||
try:
|
||||
data = request.get_json()
|
||||
if not data:
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'message': '请求数据不能为空'
|
||||
}), 400
|
||||
|
||||
result = self.config_manager.set_pressure_config(data)
|
||||
status_code = 200 if result['success'] else 400
|
||||
return jsonify(result), status_code
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f"设置压力板配置失败: {e}")
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'message': f'设置压力板配置失败: {str(e)}'
|
||||
}), 500
|
||||
|
||||
# 设置相机配置
|
||||
@self.app.route('/api/config/devices/camera', methods=['POST'])
|
||||
def set_camera_config():
|
||||
"""设置相机配置"""
|
||||
try:
|
||||
data = request.get_json()
|
||||
if not data:
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'message': '请求数据不能为空'
|
||||
}), 400
|
||||
|
||||
result = self.config_manager.set_camera_config(data)
|
||||
status_code = 200 if result['success'] else 400
|
||||
return jsonify(result), status_code
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f"设置相机配置失败: {e}")
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'message': f'设置相机配置失败: {str(e)}'
|
||||
}), 500
|
||||
|
||||
# 设置FemtoBolt配置
|
||||
@self.app.route('/api/config/devices/femtobolt', methods=['POST'])
|
||||
def set_femtobolt_config():
|
||||
"""设置FemtoBolt配置"""
|
||||
try:
|
||||
data = request.get_json()
|
||||
if not data:
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'message': '请求数据不能为空'
|
||||
}), 400
|
||||
|
||||
result = self.config_manager.set_femtobolt_config(data)
|
||||
status_code = 200 if result['success'] else 400
|
||||
return jsonify(result), status_code
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f"设置FemtoBolt配置失败: {e}")
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'message': f'设置FemtoBolt配置失败: {str(e)}'
|
||||
}), 500
|
||||
|
||||
# 重新加载配置
|
||||
@self.app.route('/api/config/reload', methods=['POST'])
|
||||
def reload_config():
|
||||
"""重新加载配置"""
|
||||
try:
|
||||
self.config_manager.reload_config()
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'message': '配置重新加载成功'
|
||||
})
|
||||
except Exception as e:
|
||||
self.logger.error(f"重新加载配置失败: {e}")
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'message': f'重新加载配置失败: {str(e)}'
|
||||
}), 500
|
||||
|
||||
# 验证配置
|
||||
@self.app.route('/api/config/validate', methods=['GET'])
|
||||
def validate_config():
|
||||
"""验证配置"""
|
||||
try:
|
||||
result = self.config_manager.validate_config()
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'data': result
|
||||
})
|
||||
except Exception as e:
|
||||
self.logger.error(f"验证配置失败: {e}")
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'message': f'验证配置失败: {str(e)}'
|
||||
}), 500
|
||||
|
||||
|
||||
# 创建独立的Flask应用用于测试
|
||||
def create_config_app():
|
||||
"""
|
||||
创建配置API应用
|
||||
|
||||
Returns:
|
||||
Flask: Flask应用实例
|
||||
"""
|
||||
app = Flask(__name__)
|
||||
|
||||
# 配置日志
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
|
||||
)
|
||||
|
||||
# 初始化配置API
|
||||
config_api = ConfigAPI(app)
|
||||
|
||||
return app
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
# 创建并运行应用
|
||||
app = create_config_app()
|
||||
app.run(host='0.0.0.0', port=5002, debug=True)
|
@ -30,7 +30,7 @@ depth_range_max = 1700
|
||||
[DEVICES]
|
||||
imu_device_type = real
|
||||
imu_port = COM3
|
||||
imu_baudrate = 9600
|
||||
imu_baudrate = 115200
|
||||
pressure_device_type = real
|
||||
pressure_use_mock = False
|
||||
pressure_port = COM5
|
||||
|
@ -43,25 +43,38 @@ class ConfigManager:
|
||||
Returns:
|
||||
str: 配置文件路径
|
||||
"""
|
||||
import sys
|
||||
|
||||
# 可能的配置文件路径
|
||||
possible_paths = [
|
||||
# os.path.join(os.path.dirname(__file__), 'config.ini')
|
||||
]
|
||||
# 配置文件路径
|
||||
possible_paths = []
|
||||
|
||||
# 如果是打包后的exe文件,从exe文件同级目录获取
|
||||
if getattr(sys, 'frozen', False):
|
||||
# 打包后的可执行文件
|
||||
possible_paths.append(os.path.join(os.path.dirname(sys.executable), 'config.ini'))
|
||||
else:
|
||||
# 开发环境
|
||||
possible_paths.append(os.path.join(os.path.dirname(__file__), 'config.ini'))
|
||||
# 打包后的exe文件路径
|
||||
exe_dir = os.path.dirname(sys.executable)
|
||||
possible_paths.append(os.path.join(exe_dir, 'config.ini'))
|
||||
|
||||
# 开发环境下的路径
|
||||
possible_paths.extend([
|
||||
os.path.join(os.path.dirname(__file__), 'config.ini'),
|
||||
os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), 'config.ini'), # backend/config.ini
|
||||
os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(__file__)))), 'config.ini') # 项目根目录/config.ini
|
||||
])
|
||||
|
||||
for path in possible_paths:
|
||||
abs_path = os.path.abspath(path)
|
||||
if os.path.exists(abs_path):
|
||||
self.logger.info(f"找到配置文件: {abs_path}")
|
||||
return abs_path
|
||||
|
||||
|
||||
|
||||
# 如果都找不到,返回默认路径(exe同级目录或backend目录)
|
||||
if getattr(sys, 'frozen', False):
|
||||
default_path = os.path.join(os.path.dirname(sys.executable), 'config.ini')
|
||||
else:
|
||||
default_path = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), 'config.ini')
|
||||
|
||||
self.logger.warning(f"未找到配置文件,使用默认路径: {default_path}")
|
||||
return default_path
|
||||
def _load_config(self):
|
||||
"""
|
||||
加载配置文件
|
||||
@ -515,4 +528,74 @@ class ConfigManager:
|
||||
'pressure': self.get_device_config('pressure'),
|
||||
'camera': self.get_device_config('camera'),
|
||||
'femtobolt': self.get_device_config('femtobolt')
|
||||
}
|
||||
}
|
||||
|
||||
def set_all_device_configs(self, configs: Dict[str, Dict[str, Any]]) -> Dict[str, Any]:
|
||||
"""
|
||||
批量设置所有设备配置
|
||||
|
||||
Args:
|
||||
configs: 所有设备配置数据
|
||||
{
|
||||
'imu': {'device_type': 'real', 'port': 'COM7', 'baudrate': 9600},
|
||||
'pressure': {'device_type': 'real', 'port': 'COM8', 'baudrate': 115200},
|
||||
'camera': {'device_index': 0, 'width': 1280, 'height': 720, 'fps': 30},
|
||||
'femtobolt': {'color_resolution': '1080P', 'depth_mode': 'NFOV_UNBINNED', 'fps': 15}
|
||||
}
|
||||
|
||||
Returns:
|
||||
Dict[str, Any]: 设置结果
|
||||
"""
|
||||
try:
|
||||
results = {}
|
||||
errors = []
|
||||
|
||||
# 逐个设置每个设备的配置
|
||||
if 'imu' in configs:
|
||||
result = self.set_imu_config(configs['imu'])
|
||||
results['imu'] = result
|
||||
if not result['success']:
|
||||
errors.append(f"IMU: {result['message']}")
|
||||
|
||||
if 'pressure' in configs:
|
||||
result = self.set_pressure_config(configs['pressure'])
|
||||
results['pressure'] = result
|
||||
if not result['success']:
|
||||
errors.append(f"压力板: {result['message']}")
|
||||
|
||||
if 'camera' in configs:
|
||||
result = self.set_camera_config(configs['camera'])
|
||||
results['camera'] = result
|
||||
if not result['success']:
|
||||
errors.append(f"相机: {result['message']}")
|
||||
|
||||
if 'femtobolt' in configs:
|
||||
result = self.set_femtobolt_config(configs['femtobolt'])
|
||||
results['femtobolt'] = result
|
||||
if not result['success']:
|
||||
errors.append(f"FemtoBolt: {result['message']}")
|
||||
|
||||
# 如果有错误,返回部分成功的结果
|
||||
if errors:
|
||||
self.logger.warning(f"部分设备配置设置失败: {'; '.join(errors)}")
|
||||
return {
|
||||
'success': False,
|
||||
'message': f'部分设备配置设置失败: {"; ".join(errors)}',
|
||||
'results': results,
|
||||
'updated_configs': self.get_all_device_configs()
|
||||
}
|
||||
else:
|
||||
self.logger.info("所有设备配置设置成功")
|
||||
return {
|
||||
'success': True,
|
||||
'message': '所有设备配置设置成功',
|
||||
'results': results,
|
||||
'updated_configs': self.get_all_device_configs()
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f"批量设置设备配置失败: {e}")
|
||||
return {
|
||||
'success': False,
|
||||
'message': f'批量设置设备配置失败: {str(e)}'
|
||||
}
|
Binary file not shown.
137
backend/main.py
137
backend/main.py
@ -223,9 +223,9 @@ class AppServer:
|
||||
self.logger.info('设备协调器初始化完成')
|
||||
|
||||
# 启动Flask应用
|
||||
host = app_config.get('host', self.host)
|
||||
port = app_config.get('port', self.port)
|
||||
debug = app_config.get('debug', self.debug)
|
||||
host = self.host
|
||||
port = self.port
|
||||
debug = self.debug
|
||||
|
||||
self.logger.info(f'启动Flask应用 - Host: {host}, Port: {port}, Debug: {debug}')
|
||||
|
||||
@ -559,15 +559,25 @@ class AppServer:
|
||||
if not data.get(field):
|
||||
return jsonify({'success': False, 'error': f'{field}不能为空'}), 400
|
||||
|
||||
patient_id = self.db_manager.create_patient(
|
||||
name=data['name'],
|
||||
gender=data['gender'],
|
||||
age=data['age'],
|
||||
height=data.get('height'),
|
||||
weight=data.get('weight'),
|
||||
medical_history=data.get('medical_history', ''),
|
||||
notes=data.get('notes', '')
|
||||
)
|
||||
patient_data = {
|
||||
'name': data['name'],
|
||||
'gender': data['gender'],
|
||||
'age': data['age'],
|
||||
'birth_date': data.get('birth_date'),
|
||||
'nationality': data.get('nationality'),
|
||||
'residence': data.get('residence'),
|
||||
'height': data.get('height'),
|
||||
'weight': data.get('weight'),
|
||||
'shoe_size': data.get('shoe_size'),
|
||||
'phone': data.get('phone'),
|
||||
'email': data.get('email'),
|
||||
'occupation': data.get('occupation'),
|
||||
'workplace': data.get('workplace'),
|
||||
'medical_history': data.get('medical_history', ''),
|
||||
'notes': data.get('notes', '')
|
||||
}
|
||||
|
||||
patient_id = self.db_manager.create_patient(patient_data)
|
||||
|
||||
if patient_id:
|
||||
return jsonify({
|
||||
@ -603,16 +613,26 @@ class AppServer:
|
||||
try:
|
||||
data = flask_request.get_json()
|
||||
|
||||
result = self.db_manager.update_patient(
|
||||
patient_id=patient_id,
|
||||
name=data.get('name'),
|
||||
gender=data.get('gender'),
|
||||
age=data.get('age'),
|
||||
height=data.get('height'),
|
||||
weight=data.get('weight'),
|
||||
medical_history=data.get('medical_history'),
|
||||
notes=data.get('notes')
|
||||
)
|
||||
patient_data = {
|
||||
'name': data.get('name'),
|
||||
'gender': data.get('gender'),
|
||||
'age': data.get('age'),
|
||||
'birth_date': data.get('birth_date'),
|
||||
'nationality': data.get('nationality'),
|
||||
'residence': data.get('residence'),
|
||||
'height': data.get('height'),
|
||||
'weight': data.get('weight'),
|
||||
'shoe_size': data.get('shoe_size'),
|
||||
'phone': data.get('phone'),
|
||||
'email': data.get('email'),
|
||||
'occupation': data.get('occupation'),
|
||||
'workplace': data.get('workplace'),
|
||||
'medical_history': data.get('medical_history'),
|
||||
'notes': data.get('notes')
|
||||
}
|
||||
|
||||
self.db_manager.update_patient(patient_id, patient_data)
|
||||
result = True
|
||||
|
||||
if result:
|
||||
return jsonify({'success': True, 'message': '患者信息更新成功'})
|
||||
@ -666,6 +686,79 @@ class AppServer:
|
||||
self.logger.error(f'刷新设备失败: {e}')
|
||||
return jsonify({'success': False, 'error': str(e)}), 500
|
||||
|
||||
# ==================== 设备配置API ====================
|
||||
|
||||
@self.app.route('/api/config/devices', methods=['GET'])
|
||||
def get_all_device_configs():
|
||||
"""获取所有设备配置"""
|
||||
try:
|
||||
if self.config_manager:
|
||||
configs = self.config_manager.get_all_device_configs()
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'data': configs
|
||||
})
|
||||
else:
|
||||
return jsonify({'success': False, 'error': '配置管理器未初始化'}), 500
|
||||
except Exception as e:
|
||||
self.logger.error(f"获取设备配置失败: {e}")
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'message': f'获取设备配置失败: {str(e)}'
|
||||
}), 500
|
||||
|
||||
@self.app.route('/api/config/devices/all', methods=['POST'])
|
||||
def set_all_device_configs():
|
||||
"""批量设置所有设备配置"""
|
||||
try:
|
||||
if not self.config_manager:
|
||||
return jsonify({'success': False, 'error': '配置管理器未初始化'}), 500
|
||||
|
||||
data = flask_request.get_json()
|
||||
if not data:
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'message': '请求数据不能为空'
|
||||
}), 400
|
||||
|
||||
# 验证数据格式
|
||||
supported_devices = ['imu', 'pressure', 'camera', 'femtobolt']
|
||||
for device_name in data.keys():
|
||||
if device_name not in supported_devices:
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'message': f'不支持的设备类型: {device_name},支持的设备类型: {", ".join(supported_devices)}'
|
||||
}), 400
|
||||
|
||||
result = self.config_manager.set_all_device_configs(data)
|
||||
|
||||
# 如果配置设置成功,重启设备数据推送
|
||||
if result['success']:
|
||||
try:
|
||||
self.logger.info("设备配置更新成功,重启设备数据推送...")
|
||||
# 先停止当前的数据推送
|
||||
if self.is_pushing_data:
|
||||
self.stop_device_push_data()
|
||||
time.sleep(1) # 等待停止完成
|
||||
|
||||
# 重新启动设备数据推送
|
||||
self.start_device_push_data()
|
||||
result['message'] = result.get('message', '') + ' 设备已重启数据推送。'
|
||||
self.logger.info("设备配置更新并重启数据推送完成")
|
||||
except Exception as restart_error:
|
||||
self.logger.error(f"重启设备数据推送失败: {restart_error}")
|
||||
result['message'] = result.get('message', '') + f' 但重启设备数据推送失败: {str(restart_error)}'
|
||||
|
||||
status_code = 200 if result['success'] else 400
|
||||
return jsonify(result), status_code
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f"批量设置设备配置失败: {e}")
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'message': f'批量设置设备配置失败: {str(e)}'
|
||||
}), 500
|
||||
|
||||
@self.app.route('/api/devices/calibrate', methods=['POST'])
|
||||
def calibrate_device():
|
||||
"""校准设备"""
|
||||
|
@ -1,40 +0,0 @@
|
||||
[08/18 20:41:43.488456][debug][24904][Context.cpp:30] Context creating, work_dir=D:\Trae_space\BodyBalanceEvaluation\frontend\src\renderer\dist-electron\win-unpacked\resources\backend
|
||||
[08/18 20:41:43.488655][debug][24904][Context.cpp:49] Config file version=1.1
|
||||
[08/18 20:41:43.488739][debug][24904][FrameBufferManager.cpp:23] Max global frame buffer size updated! size=2048.000MB
|
||||
[08/18 20:41:43.488782][info][24904][Context.cpp:68] Context created with config: default config!
|
||||
[08/18 20:41:43.488823][info][24904][Context.cpp:73] Work directory=D:\Trae_space\BodyBalanceEvaluation\frontend\src\renderer\dist-electron\win-unpacked\resources\backend, SDK version=v1.10.11-20240724-aeaa107e5
|
||||
[08/18 20:41:43.489074][debug][24904][DeviceManager.cpp:30] DeviceManager init ...
|
||||
[08/18 20:41:43.489100][info][24904][MfPal.cpp:105] createObPal: create WinPal!
|
||||
[08/18 20:41:43.489124][debug][24904][MfPal.cpp:110] WmfPal init ...
|
||||
[08/18 20:41:43.520661][debug][24904][MfPal.cpp:117] WmfPal created!
|
||||
[08/18 20:41:43.520721][debug][24904][DeviceManager.cpp:34] Enable USB Device Enumerator ...
|
||||
[08/18 20:41:43.553521][debug][24904][EnumeratorLibusb.cpp:321] queryDevicesInfo done!
|
||||
[08/18 20:41:43.553940][debug][24904][MfPal.cpp:216] Create WinEventDeviceWatcher!
|
||||
[08/18 20:41:43.554220][debug][24904][UsbDeviceEnumerator.cpp:78] No matched usb device found!
|
||||
[08/18 20:41:43.554276][info][24904][DeviceManager.cpp:15] Current found device(s): (0)
|
||||
[08/18 20:41:43.554305][debug][24904][DeviceManager.cpp:52] DeviceManager construct done!
|
||||
[08/18 20:41:43.554347][debug][24904][Context.cpp:81] Context destroying ...
|
||||
[08/18 20:41:43.554360][debug][24904][DeviceManager.cpp:56] DeviceManager destroy ...
|
||||
[08/18 20:41:43.554371][debug][24904][DeviceManager.cpp:64] DeviceManager Destructors done
|
||||
[08/18 20:41:43.558317][debug][24904][MfPal.cpp:128] WmfPal destroyed!
|
||||
[08/18 20:41:43.558735][info][24904][Context.cpp:84] Context destroyed
|
||||
[08/18 20:43:03.299275][debug][29780][Context.cpp:30] Context creating, work_dir=D:\Trae_space\BodyBalanceEvaluation\frontend\src\renderer\dist-electron\win-unpacked\resources\backend
|
||||
[08/18 20:43:03.299338][debug][29780][Context.cpp:49] Config file version=1.1
|
||||
[08/18 20:43:03.299358][debug][29780][FrameBufferManager.cpp:23] Max global frame buffer size updated! size=2048.000MB
|
||||
[08/18 20:43:03.299375][info][29780][Context.cpp:68] Context created with config: default config!
|
||||
[08/18 20:43:03.299399][info][29780][Context.cpp:73] Work directory=D:\Trae_space\BodyBalanceEvaluation\frontend\src\renderer\dist-electron\win-unpacked\resources\backend, SDK version=v1.10.11-20240724-aeaa107e5
|
||||
[08/18 20:43:03.299416][debug][29780][DeviceManager.cpp:30] DeviceManager init ...
|
||||
[08/18 20:43:03.299428][info][29780][MfPal.cpp:105] createObPal: create WinPal!
|
||||
[08/18 20:43:03.299441][debug][29780][MfPal.cpp:110] WmfPal init ...
|
||||
[08/18 20:43:03.340690][debug][29780][MfPal.cpp:117] WmfPal created!
|
||||
[08/18 20:43:03.340727][debug][29780][DeviceManager.cpp:34] Enable USB Device Enumerator ...
|
||||
[08/18 20:43:03.367003][debug][29780][EnumeratorLibusb.cpp:321] queryDevicesInfo done!
|
||||
[08/18 20:43:03.367322][debug][29780][MfPal.cpp:216] Create WinEventDeviceWatcher!
|
||||
[08/18 20:43:03.367577][debug][29780][UsbDeviceEnumerator.cpp:78] No matched usb device found!
|
||||
[08/18 20:43:03.367605][info][29780][DeviceManager.cpp:15] Current found device(s): (0)
|
||||
[08/18 20:43:03.367629][debug][29780][DeviceManager.cpp:52] DeviceManager construct done!
|
||||
[08/18 20:43:03.367646][debug][29780][Context.cpp:81] Context destroying ...
|
||||
[08/18 20:43:03.367657][debug][29780][DeviceManager.cpp:56] DeviceManager destroy ...
|
||||
[08/18 20:43:03.367667][debug][29780][DeviceManager.cpp:64] DeviceManager Destructors done
|
||||
[08/18 20:43:03.369012][debug][29780][MfPal.cpp:128] WmfPal destroyed!
|
||||
[08/18 20:43:03.369386][info][29780][Context.cpp:84] Context destroyed
|
1
frontend/src/renderer/src/assets/svg/avatar.svg
Normal file
1
frontend/src/renderer/src/assets/svg/avatar.svg
Normal file
@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1755591402762" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7849" xmlns:xlink="http://www.w3.org/1999/xlink" width="32" height="32"><path d="M512 512a256 256 0 1 0-257.28-256A256 256 0 0 0 512 512z m0 128c-171.52 0-512 82.651429-512 256v128h1024v-128c2.742857-173.348571-337.737143-256-512-256z" fill="#ffffff" p-id="7850"></path></svg>
|
After Width: | Height: | Size: 526 B |
BIN
frontend/src/renderer/src/assets/sz.png
Normal file
BIN
frontend/src/renderer/src/assets/sz.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.5 KiB |
@ -13,7 +13,7 @@ api.interceptors.request.use(
|
||||
if (window.electronAPI) {
|
||||
config.baseURL = window.electronAPI.getBackendUrl()
|
||||
} else {
|
||||
config.baseURL = 'http://localhost:5000'
|
||||
config.baseURL = 'http://192.168.1.58:5000'
|
||||
}
|
||||
|
||||
// 只为需要发送数据的请求设置Content-Type
|
||||
@ -607,7 +607,7 @@ export const getBackendUrl = () => {
|
||||
if (window.electronAPI) {
|
||||
return window.electronAPI.getBackendUrl()
|
||||
} else {
|
||||
return 'http://localhost:5000'
|
||||
return 'http://192.168.1.58:5000'
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7,8 +7,8 @@
|
||||
起始页
|
||||
</div>
|
||||
<div class="main-dashboard-top-info">
|
||||
<div>测试时间:2025-08-03 17:13:18<span></span></div>
|
||||
<div style="margin-left: 15px;">测试医生:<span>李医生</span></div>
|
||||
<!-- <div>测试时间:2025-08-03 17:13:18<span></span></div>
|
||||
<div style="margin-left: 15px;">测试医生:<span>李医生</span></div> -->
|
||||
</div>
|
||||
</div>
|
||||
<!-- 左侧功能导航 -->
|
||||
@ -29,7 +29,7 @@
|
||||
</div>
|
||||
<div class="search-box">
|
||||
<el-input v-model="searchKeyword" placeholder="搜索患者姓名" prefix-icon="Search" clearable
|
||||
@input="handleSearch" />
|
||||
@input="handleSearch" class="search-input"/>
|
||||
</div>
|
||||
</div>
|
||||
<el-table ref="tableRef" :data="filteredPatients" style="width: 100%" border @cell-click="selectPatient"
|
||||
@ -62,7 +62,7 @@
|
||||
<div class="module-title-text">基础信息</div>
|
||||
</div>
|
||||
<el-button link @click="editPatient">
|
||||
<el-icon>
|
||||
<el-icon class="edit-icon" style="width: 28px;height: 28px;font-size: 28px;cursor: pointer;color: #CCCCCC;">
|
||||
<Edit />
|
||||
</el-icon>
|
||||
</el-button>
|
||||
@ -139,7 +139,8 @@
|
||||
<!-- 无选中患者时的提示 -->
|
||||
<div class="no-selection" v-else>
|
||||
<el-empty description="请选择一个患者查看详情">
|
||||
<el-button type="primary" @click="createNewPatient">新建患者档案</el-button>
|
||||
<!-- <el-button type="primary" @click="createNewPatient">新建患者档案</el-button> -->
|
||||
<div class="action-view-buttons" style="width:338px;" @click="createNewPatient">+新患者建档</div>
|
||||
</el-empty>
|
||||
</div>
|
||||
</div>
|
||||
@ -183,8 +184,8 @@
|
||||
<el-col :span="12">
|
||||
<el-form-item label="民族" prop="nationality">
|
||||
<el-select v-model="patientForm.nationality" placeholder="请选择">
|
||||
<el-option v-for="item in nationalityOptions" :key="item.value" :label="item.label"
|
||||
:value="item.value" />
|
||||
<el-option v-for="item in nationalityOptions" :key="item" :label="item"
|
||||
:value="item" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
@ -228,8 +229,8 @@
|
||||
<el-col :span="12">
|
||||
<el-form-item label="职业" prop="occupation">
|
||||
<el-select v-model="patientForm.occupation" placeholder="请选择">
|
||||
<el-option v-for="item in occupationOptions" :key="item.value" :label="item.label"
|
||||
:value="item.value" />
|
||||
<el-option v-for="item in occupationOptions" :key="item" :label="item"
|
||||
:value="item" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
@ -294,15 +295,23 @@ const patientForm = ref({
|
||||
workplace: '',
|
||||
email: ''
|
||||
})
|
||||
const occupationOptions = ref([
|
||||
{ label: '学生', value: '学生' }
|
||||
])
|
||||
const occupationOptions = ref(["学生", "教师", "医生", "护士", "工程师", "程序员", "设计师",
|
||||
"会计师", "律师", "警察", "消防员", "军人", "公务员", "销售", "市场营销",
|
||||
"人力资源", "行政", "财务", "咨询师", "建筑师", "科研人员", "记者", "编辑",
|
||||
"作家", "艺术家", "音乐家", "演员", "导演", "摄影师", "厨师", "服务员",
|
||||
"司机", "快递员", "外卖员", "农民", "工人", "电工", "焊工", "机械师",
|
||||
"飞行员", "空乘", "船员", "导游", "翻译", "心理咨询师", "社会工作者",
|
||||
"运动员", "教练", "经纪人", "投资人", "企业家", "自由职业者"])
|
||||
const residenceOptions = ref([
|
||||
{ label: '北京', value: '北京' }
|
||||
])
|
||||
const nationalityOptions = ref([
|
||||
{ label: '汉族', value: '汉族' }
|
||||
])
|
||||
const nationalityOptions = ref(["汉族", "满族", "蒙古族", "回族", "藏族", "维吾尔族", "苗族", "彝族", "壮族",
|
||||
"布依族", "朝鲜族", "侗族", "瑶族", "白族", "土家族", "哈尼族", "哈萨克族", "傣族",
|
||||
"黎族", "傈僳族", "佤族", "畲族", "高山族", "拉祜族", "水族", "东乡族", "纳西族",
|
||||
"景颇族", "柯尔克孜族", "土族", "达斡尔族", "仫佬族", "羌族", "布朗族", "撒拉族",
|
||||
"毛南族", "仡佬族", "锡伯族", "阿昌族", "普米族", "塔吉克族", "怒族", "乌孜别克族",
|
||||
"俄罗斯族", "鄂温克族", "德昂族", "保安族", "裕固族", "京族", "塔塔尔族", "独龙族",
|
||||
"鄂伦春族", "赫哲族", "门巴族", "珞巴族", "基诺族"])
|
||||
// 表单验证规则
|
||||
const formRules = {
|
||||
name: [
|
||||
@ -1073,10 +1082,12 @@ function delClick(id) {
|
||||
|
||||
:deep(.el-input__inner) {
|
||||
color: #ffffff;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
:deep(.el-select__placeholder) {
|
||||
color: #ffffff;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
:deep(.el-input.is-disabled .el-input__wrapper) {
|
||||
@ -1191,4 +1202,7 @@ function delClick(id) {
|
||||
font-size: 20px;
|
||||
font-family: 'Arial Normal', 'Arial', sans-serif;
|
||||
}
|
||||
</style>
|
||||
.search-input{
|
||||
font-size: 16px;
|
||||
}
|
||||
</style>
|
||||
|
@ -11,33 +11,36 @@
|
||||
<!-- <el-icon class="back-icon" @click="handleBack"><ArrowLeft /></el-icon> -->
|
||||
<span class="page-title">实时检测</span>
|
||||
</div>
|
||||
|
||||
<img src="@/assets/sz.png" alt="" title="编辑相机参数" style="margin-left: 20px;cursor: pointer; width: 24px;height: 24px;"
|
||||
@click="cameraUpdate">
|
||||
|
||||
|
||||
<!-- 录制时间 -->
|
||||
<div v-if="isRecording" class="icon-container">
|
||||
<img src="@/assets/record.png" class="blink-icon" :class="{ blinking: isRunning }" alt="">
|
||||
<div style="font-size: 18px;">{{ formattedTime }}</div>
|
||||
</div>
|
||||
<el-button v-if="!isRecording" @click="handleStartStop" :disabled="!isConnected" type="primary"
|
||||
class="start-btn" style="background-image: linear-gradient(to right, rgb(236, 50, 166), rgb(160, 5, 216));
|
||||
class="start-title-btn" style="background-image: linear-gradient(to right, rgb(236, 50, 166), rgb(160, 5, 216));
|
||||
--el-button-border-color: #409EFF;
|
||||
--el-button-border-color: transparent;width: 120px;height: 30px;font-size: 20px;">
|
||||
{{ isConnected ? '开始' : '连接中...' }}
|
||||
</el-button>
|
||||
<!-- handleStartStop -->
|
||||
<el-button v-if="isRecording" @click="handleStartStop" type="primary" class="start-btn" style="background-image: linear-gradient(to right, rgb(236, 50, 166), rgb(160, 5, 216));
|
||||
<el-button v-if="isRecording" @click="handleStartStop" type="primary" class="start-title-btn" style="background-image: linear-gradient(to right, rgb(236, 50, 166), rgb(160, 5, 216));
|
||||
--el-button-border-color: #409EFF;
|
||||
--el-button-border-color: transparent;width: 120px;height: 30px;font-size: 20px;">
|
||||
结束
|
||||
</el-button>
|
||||
<el-button v-if="isStart && isConnected" @click="saveDetectionData" type="primary" class="start-btn" style="background-image: linear-gradient(to right, #FBB106, #A817C6);
|
||||
<el-button v-if="isStart && isConnected" @click="saveDetectionData" type="primary" class="start-title-btn" style="background-image: linear-gradient(to right, #FBB106, #A817C6);
|
||||
--el-button-border-color: #409EFF;
|
||||
--el-button-border-color: transparent;width: 120px;height: 30px;font-size: 20px;">
|
||||
保存数据
|
||||
</el-button>
|
||||
</div>
|
||||
|
||||
<div class="top-bar-right">
|
||||
<span class="info-item">测试时间:2025/5/28 下午14:38</span>
|
||||
<span class="info-item">测试医生:李四</span>
|
||||
<div class="top-bar-right">
|
||||
<el-icon class="top-icon">
|
||||
<Clock />
|
||||
</el-icon>
|
||||
@ -64,7 +67,7 @@
|
||||
<div style="display: flex;justify-content: center;height: 100%;padding-top: 0px;">
|
||||
<!-- 使用深度相机视频流替换静态图片 -->
|
||||
<img :src="(femtoboltStatus === '已连接' && depthCameraImgSrc) ? depthCameraImgSrc : noImageSvg" alt="深度相机视频流"
|
||||
style="width: 100%;height: calc(100% - 10px);object-fit:contain;background:#323232;">
|
||||
style="width: 100%;height: calc(100% - 40px);object-fit:contain;background:#323232;">
|
||||
</div>
|
||||
</div>
|
||||
<div class="body-posture" style="width: 45%;display: flex;margin-right: 1px;
|
||||
@ -415,8 +418,8 @@
|
||||
<el-col :span="12">
|
||||
<el-form-item label="民族" prop="nationality">
|
||||
<el-select v-model="patientForm.nationality" placeholder="请选择">
|
||||
<el-option v-for="item in nationalityOptions" :key="item.value" :label="item.label"
|
||||
:value="item.value" />
|
||||
<el-option v-for="item in nationalityOptions" :key="item" :label="item"
|
||||
:value="item" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
@ -460,8 +463,8 @@
|
||||
<el-col :span="12">
|
||||
<el-form-item label="职业" prop="occupation">
|
||||
<el-select v-model="patientForm.occupation" placeholder="请选择">
|
||||
<el-option v-for="item in occupationOptions" :key="item.value" :label="item.label"
|
||||
:value="item.value" />
|
||||
<el-option v-for="item in occupationOptions" :key="item" :label="item"
|
||||
:value="item" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
@ -483,6 +486,63 @@
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
|
||||
<el-dialog class="tsDialog" v-model="cameraDialogVisible" center title="诊断信息" width="600"
|
||||
:before-close="cameraHandleClose">
|
||||
<div class="form-box" style="margin-top: 20px;">
|
||||
<el-form :model="cameraForm" label-width="100px">
|
||||
<div class="cameraFormTitle">足部相机</div>
|
||||
<el-form-item label="序号">
|
||||
<el-radio-group v-model="cameraForm.camera.device_index">
|
||||
<el-radio :value="0">0</el-radio>
|
||||
<el-radio :value="1">1</el-radio>
|
||||
<el-radio :value="2">2</el-radio>
|
||||
<el-radio :value="3">3</el-radio>
|
||||
<el-radio :value="4">4</el-radio>
|
||||
<el-radio :value="5">5</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<div class="cameraFormTitle">深度相机</div>
|
||||
|
||||
<el-form-item label="距离范围">
|
||||
<div >
|
||||
<el-input v-model="cameraForm.femtobolt.depth_range_min" placeholder="请输入最小值" style="width: 216px;" />
|
||||
<span> 到 </span>
|
||||
<el-input v-model="cameraForm.femtobolt.depth_range_max" placeholder="请输入最大值" style="width: 218px;"/>
|
||||
</div>
|
||||
|
||||
</el-form-item>
|
||||
<div class="cameraFormTitle">头部IMU</div>
|
||||
<el-form-item label="IMU串口号">
|
||||
<el-select v-model="cameraForm.imu.port" placeholder="请选择">
|
||||
<el-option label="COM1" value="COM1" />
|
||||
<el-option label="COM2" value="COM2" />
|
||||
<el-option label="COM3" value="COM3" />
|
||||
<el-option label="COM4" value="COM4" />
|
||||
<el-option label="COM5" value="COM5" />
|
||||
<el-option label="COM6" value="COM6" />
|
||||
<el-option label="COM7" value="COM7" />
|
||||
<el-option label="COM8" value="COM8" />
|
||||
<el-option label="COM9" value="COM9" />
|
||||
<el-option label="COM10" value="COM10" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button style="background: #323232;border:1px solid #787878;color: #ffffff;"
|
||||
@click="cameraDialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" style="background:#0099ff;" @click="cameraSubmit('cameraForm')">
|
||||
保存
|
||||
</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -507,6 +567,7 @@ const depthCameraImgSrc = ref('') // 深度相机视频流
|
||||
const screenshotLoading = ref(false)
|
||||
const dataCollectionLoading = ref(false)
|
||||
const isRecording = ref(false)
|
||||
const cameraDialogVisible =ref(false) // 设置相机参数弹框
|
||||
|
||||
// 录像相关变量
|
||||
let mediaRecorder = null
|
||||
@ -545,6 +606,9 @@ const resDialogVisible = ref(false)
|
||||
const reshandleClose = () => {
|
||||
resDialogVisible.value = false
|
||||
}
|
||||
const cameraHandleClose = () => {
|
||||
cameraDialogVisible.value = false
|
||||
}
|
||||
const dialogVisible = ref(false)
|
||||
const handleClose = () => {
|
||||
dialogVisible.value = false
|
||||
@ -568,17 +632,38 @@ const patientForm = ref({
|
||||
workplace: '',
|
||||
email: ''
|
||||
})
|
||||
const occupationOptions = ref([
|
||||
{ label: '学生', value: '学生' }
|
||||
])
|
||||
const nationalityOptions = ref([
|
||||
{ label: '汉族', value: '汉族' }
|
||||
])
|
||||
const occupationOptions = ref(["学生", "教师", "医生", "护士", "工程师", "程序员", "设计师",
|
||||
"会计师", "律师", "警察", "消防员", "军人", "公务员", "销售", "市场营销",
|
||||
"人力资源", "行政", "财务", "咨询师", "建筑师", "科研人员", "记者", "编辑",
|
||||
"作家", "艺术家", "音乐家", "演员", "导演", "摄影师", "厨师", "服务员",
|
||||
"司机", "快递员", "外卖员", "农民", "工人", "电工", "焊工", "机械师",
|
||||
"飞行员", "空乘", "船员", "导游", "翻译", "心理咨询师", "社会工作者",
|
||||
"运动员", "教练", "经纪人", "投资人", "企业家", "自由职业者"])
|
||||
const nationalityOptions = ref(["汉族", "满族", "蒙古族", "回族", "藏族", "维吾尔族", "苗族", "彝族", "壮族",
|
||||
"布依族", "朝鲜族", "侗族", "瑶族", "白族", "土家族", "哈尼族", "哈萨克族", "傣族",
|
||||
"黎族", "傈僳族", "佤族", "畲族", "高山族", "拉祜族", "水族", "东乡族", "纳西族",
|
||||
"景颇族", "柯尔克孜族", "土族", "达斡尔族", "仫佬族", "羌族", "布朗族", "撒拉族",
|
||||
"毛南族", "仡佬族", "锡伯族", "阿昌族", "普米族", "塔吉克族", "怒族", "乌孜别克族",
|
||||
"俄罗斯族", "鄂温克族", "德昂族", "保安族", "裕固族", "京族", "塔塔尔族", "独龙族",
|
||||
"鄂伦春族", "赫哲族", "门巴族", "珞巴族", "基诺族"])
|
||||
const diagnosticForm = ref({
|
||||
diagnosis_info: '',
|
||||
treatment_info: '',
|
||||
suggestion_info: ''
|
||||
})
|
||||
const cameraForm = ref({ // 相机参数
|
||||
camera:{
|
||||
device_index: '', // 序号
|
||||
},
|
||||
femtobolt:{
|
||||
depth_mode: '', // 相机模式
|
||||
depth_range_min: '', // 距离范围最小值
|
||||
depth_range_max: '', // 距离范围最大值
|
||||
},
|
||||
imu:{
|
||||
port: '', // IMU串口号
|
||||
}
|
||||
})
|
||||
const calculatedAge = ref(null)
|
||||
//修改
|
||||
|
||||
@ -782,6 +867,24 @@ const savePatient = async () => {
|
||||
function routeTo(path) {
|
||||
router.push(`/`)
|
||||
}
|
||||
function cameraUpdate() { // 相机设置数据更新弹框
|
||||
cameraForm.value = { // 相机参数
|
||||
camera:{
|
||||
device_index: '', // 序号
|
||||
},
|
||||
femtobolt:{
|
||||
depth_mode: '', // 相机模式
|
||||
depth_range_min: '', // 距离范围最小值
|
||||
depth_range_max: '', // 距离范围最大值
|
||||
},
|
||||
imu:{
|
||||
port: '', // IMU串口号
|
||||
}
|
||||
}
|
||||
// 加载相机参数信息
|
||||
getDevicesInit()
|
||||
|
||||
}
|
||||
const calculateAge = (birthDate) => {
|
||||
if (!birthDate) return '-'
|
||||
const today = new Date()
|
||||
@ -2152,6 +2255,59 @@ const calibrationClick = async () => {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const cameraSubmit = async () => {
|
||||
|
||||
// let data = {
|
||||
// "imu": {"device_type": "real", "port": "COM7", "baudrate": 9600},
|
||||
// "pressure": {"device_type": "real", "port": "COM8", "baudrate": 115200},
|
||||
// "camera": {"device_index": 0, "width": 1280, "height": 720, "fps": 30},
|
||||
// "femtobolt": {"color_resolution": "1080P", "depth_mode": "NFOV_UNBINNED", "fps": 15}
|
||||
// }
|
||||
|
||||
//
|
||||
const response = await fetch(`${BACKEND_URL}/api/config/devices/all`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(cameraForm.value)
|
||||
})
|
||||
if (response.ok) {
|
||||
const result = await response.json()
|
||||
if (result.success) {
|
||||
ElMessage.success(result.message)
|
||||
cameraDialogVisible.value = false
|
||||
} else {
|
||||
ElMessage.error(result.message)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 加载相机参数信息
|
||||
const getDevicesInit = async () => {
|
||||
try {
|
||||
// 调用API获取患者信息
|
||||
const response = await fetch(`${BACKEND_URL}/api/config/devices`)
|
||||
if (response.ok) {
|
||||
const result = await response.json()
|
||||
if (result.success) {
|
||||
console.log('相机参数加载成功:', result.data)
|
||||
cameraForm.value = result.data
|
||||
cameraDialogVisible.value = true
|
||||
// console.log('相机参数加载成功:', patientInfo.value)
|
||||
} else {
|
||||
throw new Error(result.message)
|
||||
}
|
||||
} else {
|
||||
throw new Error(`HTTP ${response.status}: ${response.statusText}`)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载相机参数失败:', error)
|
||||
ElMessage.warning('加载相机参数失败,请检查网络连接')
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
// 加载患者信息
|
||||
loadPatientInfo()
|
||||
@ -2294,6 +2450,12 @@ onUnmounted(() => {
|
||||
margin-left: 40px;
|
||||
}
|
||||
|
||||
.start-title-btn {
|
||||
font-size: 16px;
|
||||
padding: 8px 24px;
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
.top-bar-right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@ -2722,11 +2884,11 @@ onUnmounted(() => {
|
||||
}
|
||||
|
||||
:deep(.el-form-item__label) {
|
||||
color: #ffffff !important;
|
||||
font-size: 14px !important;
|
||||
font-family: '苹方 粗体', '苹方 中等', '苹方', sans-serif !important;
|
||||
font-weight: 700 !important;
|
||||
font-style: normal !important;
|
||||
color: #ffffff ;
|
||||
font-size: 16px ;
|
||||
font-family: '苹方 粗体', '苹方 中等', '苹方', sans-serif ;
|
||||
/* font-weight: 700 ; */
|
||||
font-style: normal ;
|
||||
}
|
||||
|
||||
|
||||
@ -2870,6 +3032,7 @@ onUnmounted(() => {
|
||||
}
|
||||
|
||||
:deep(.tsDialog.el-dialog .el-select__wrapper) {
|
||||
font-size: 16px;
|
||||
background-color: #242424;
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
@ -2901,6 +3064,18 @@ onUnmounted(() => {
|
||||
:deep(.el-dialog__footer) {
|
||||
padding: 0px 20px;
|
||||
}
|
||||
:deep(.el-radio__label){
|
||||
font-size: 16px;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
|
||||
.cameraFormTitle{
|
||||
font-size: 18px;
|
||||
color: #fff;
|
||||
font-weight: 700;
|
||||
margin: 30px 0px;
|
||||
}
|
||||
</style>
|
||||
<style>
|
||||
.dashboard-container.dashboard-container-home .el-table--border .el-table__inner-wrapper:after,
|
||||
@ -2958,4 +3133,5 @@ onUnmounted(() => {
|
||||
border-radius: 20px;
|
||||
width: 220px;
|
||||
}
|
||||
|
||||
</style>
|
@ -9,12 +9,15 @@
|
||||
<div class="system-title">平衡体态检测系统</div>
|
||||
</div>
|
||||
<div class="header-right">
|
||||
<div style="color:#fff;margin-right: 20px;">登录时间:{{ time }} </div>
|
||||
|
||||
<div class="user-info">
|
||||
<el-avatar :size="40" :src="userInfo.avatar">
|
||||
<img src="@/assets/svg/avatar.svg" alt="Avatar" style="width: 20px;height: 20px;">
|
||||
<!-- <el-avatar :size="40" :src="userInfo.avatar">
|
||||
<el-icon>
|
||||
<User />
|
||||
</el-icon>
|
||||
</el-avatar>
|
||||
</el-avatar> -->
|
||||
<span class="username">{{ userInfo.username }}</span>
|
||||
<el-dropdown @command="handleUserCommand">
|
||||
<el-button link class="user-dropdown">
|
||||
@ -44,6 +47,7 @@
|
||||
|
||||
const router = useRouter()
|
||||
const authStore = useAuthStore()
|
||||
const time = ref("");
|
||||
const userInfo = reactive({
|
||||
username: '医生',
|
||||
avatar: ''
|
||||
@ -63,7 +67,21 @@
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
function dateFormat(row) {
|
||||
const daterc = row;
|
||||
if (daterc != null) {
|
||||
var date = new Date(daterc);
|
||||
var year = date.getFullYear();
|
||||
var month = date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1;
|
||||
date.getMonth() + 1 < 10 ? "0" + (date.getMonth() + 1) : date.getMonth() + 1;
|
||||
var day = date.getDate() < 10 ? "0" + date.getDate() : date.getDate();
|
||||
var hours = date.getHours() < 10 ? "0" + date.getHours() : date.getHours();
|
||||
var minutes = date.getMinutes() < 10 ? "0" + date.getMinutes() : date.getMinutes();
|
||||
var seconds = date.getSeconds() < 10 ? "0" + date.getSeconds() : date.getSeconds();
|
||||
// 拼接
|
||||
return year + "-" + month + "-" + day + " " + hours + ":" + minutes + ":" + seconds;
|
||||
}
|
||||
}
|
||||
const handleLogout = async () => {
|
||||
try {
|
||||
await ElMessageBox.confirm('确定要退出登录吗?', '提示', {
|
||||
@ -87,11 +105,11 @@
|
||||
// 从认证状态管理中加载用户信息
|
||||
if (authStore.currentUser) {
|
||||
Object.assign(userInfo, {
|
||||
username: authStore.currentUser.username,
|
||||
username: authStore.currentUser.name,
|
||||
avatar: authStore.currentUser.avatar || ''
|
||||
})
|
||||
}
|
||||
|
||||
time.value = dateFormat(new Date())
|
||||
})
|
||||
</script>
|
||||
|
||||
|
@ -217,7 +217,8 @@ import { useAuthStore } from '../stores'
|
||||
import { User, Lock, View, Hide, Phone } from '@element-plus/icons-vue'
|
||||
|
||||
import bg from '@/assets/bg.png'
|
||||
|
||||
import { getBackendUrl } from '../services/api.js'
|
||||
const BACKEND_URL = getBackendUrl()
|
||||
const router = useRouter()
|
||||
const authStore = useAuthStore()
|
||||
|
||||
@ -487,7 +488,7 @@ const handleForgotPasswordSubmit = async () => {
|
||||
|
||||
try {
|
||||
// 调用后端API验证用户信息并获取密码
|
||||
const response = await fetch('http://127.0.0.1:5000/api/auth/forgot-password', {
|
||||
const response = await fetch( `${BACKEND_URL}/api/auth/forgot-password`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
|
@ -9,8 +9,8 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-container-info">
|
||||
<div>测试时间:2025-08-03 17:13:18<span></span></div>
|
||||
<div style="margin-left: 15px;">测试医生:<span>李医生</span></div>
|
||||
<!-- <div>测试时间:2025-08-03 17:13:18<span></span></div>
|
||||
<div style="margin-left: 15px;">测试医生:<span>李医生</span></div> -->
|
||||
</div>
|
||||
</div>
|
||||
<!-- 表单内容 -->
|
||||
@ -59,8 +59,8 @@
|
||||
<el-col :span="12">
|
||||
<el-form-item label="民族" prop="nationality">
|
||||
<el-select v-model="patientForm.nationality" placeholder="请选择">
|
||||
<el-option v-for="item in nationalityOptions" :key="item.value" :label="item.label"
|
||||
:value="item.value" />
|
||||
<el-option v-for="item in nationalityOptions" :key="item" :label="item"
|
||||
:value="item" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
@ -104,8 +104,8 @@
|
||||
<el-col :span="12">
|
||||
<el-form-item label="职业" prop="occupation">
|
||||
<el-select v-model="patientForm.occupation" placeholder="请选择">
|
||||
<el-option v-for="item in occupationOptions" :key="item.value" :label="item.label"
|
||||
:value="item.value" />
|
||||
<el-option v-for="item in occupationOptions" :key="item" :label="item"
|
||||
:value="item" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
@ -163,15 +163,23 @@ const patientForm = reactive({
|
||||
workplace: '',
|
||||
email: ''
|
||||
})
|
||||
const occupationOptions = ref([
|
||||
{ label: '学生', value: '学生' }
|
||||
])
|
||||
const occupationOptions = ref(["学生", "教师", "医生", "护士", "工程师", "程序员", "设计师",
|
||||
"会计师", "律师", "警察", "消防员", "军人", "公务员", "销售", "市场营销",
|
||||
"人力资源", "行政", "财务", "咨询师", "建筑师", "科研人员", "记者", "编辑",
|
||||
"作家", "艺术家", "音乐家", "演员", "导演", "摄影师", "厨师", "服务员",
|
||||
"司机", "快递员", "外卖员", "农民", "工人", "电工", "焊工", "机械师",
|
||||
"飞行员", "空乘", "船员", "导游", "翻译", "心理咨询师", "社会工作者",
|
||||
"运动员", "教练", "经纪人", "投资人", "企业家", "自由职业者"])
|
||||
const residenceOptions = ref([
|
||||
{ label: '北京', value: '北京' }
|
||||
])
|
||||
const nationalityOptions = ref([
|
||||
{ label: '汉族', value: '汉族' }
|
||||
])
|
||||
const nationalityOptions = ref(["汉族", "满族", "蒙古族", "回族", "藏族", "维吾尔族", "苗族", "彝族", "壮族",
|
||||
"布依族", "朝鲜族", "侗族", "瑶族", "白族", "土家族", "哈尼族", "哈萨克族", "傣族",
|
||||
"黎族", "傈僳族", "佤族", "畲族", "高山族", "拉祜族", "水族", "东乡族", "纳西族",
|
||||
"景颇族", "柯尔克孜族", "土族", "达斡尔族", "仫佬族", "羌族", "布朗族", "撒拉族",
|
||||
"毛南族", "仡佬族", "锡伯族", "阿昌族", "普米族", "塔吉克族", "怒族", "乌孜别克族",
|
||||
"俄罗斯族", "鄂温克族", "德昂族", "保安族", "裕固族", "京族", "塔塔尔族", "独龙族",
|
||||
"鄂伦春族", "赫哲族", "门巴族", "珞巴族", "基诺族"])
|
||||
// 表单验证规则
|
||||
const formRules = {
|
||||
name: [
|
||||
@ -504,10 +512,12 @@ const handleSaveAndDetect = async () => {
|
||||
|
||||
:deep(.el-input__inner) {
|
||||
color: #ffffff;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
:deep(.el-select__placeholder) {
|
||||
color: #ffffff;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
:deep(.el-input.is-disabled .el-input__wrapper) {
|
||||
|
@ -10,8 +10,8 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-container-info">
|
||||
<div>测试时间:2025-08-03 17:13:18<span></span></div>
|
||||
<div style="margin-left: 15px;">测试医生:<span>李医生</span></div>
|
||||
<!-- <div>测试时间:2025-08-03 17:13:18<span></span></div>
|
||||
<div style="margin-left: 15px;">测试医生:<span>李医生</span></div> -->
|
||||
</div>
|
||||
</div>
|
||||
<div class="main-content">
|
||||
|
@ -1473,6 +1473,7 @@ onUnmounted(() => {
|
||||
|
||||
:deep(.el-input__inner) {
|
||||
color: #fff;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
:deep(.el-textarea__inner) {
|
||||
|
Loading…
Reference in New Issue
Block a user