清理了屏幕录制,截图相关方法。调整了系统启动逻辑。

This commit is contained in:
root 2026-01-11 11:38:02 +08:00
parent 9f2ecf02c4
commit 685765e2b2
7 changed files with 95 additions and 1177 deletions

View File

@ -29,8 +29,8 @@ fourcc = MJPG
backend = directshow
[CAMERA2]
enable = True
device_index = 1
enable = False
device_index = 2
width = 1280
height = 720
fps = 30

View File

@ -1096,22 +1096,18 @@ class DatabaseManager:
"""保存检测视频记录(与 detection_video 表结构保持一致)"""
conn = self.get_connection()
cursor = conn.cursor()
try:
video_id = self.generate_detection_video_id()
china_time = self.get_china_time()
cursor.execute('''
INSERT INTO detection_video (
id, session_id, screen_video, body_video, foot_video1, foot_video2, timestamp
) VALUES (?, ?, ?, ?, ?, ?, ?)
id, session_id, screen_video, timestamp
) VALUES (?, ?, ?, ?)
''', (
video_id,
session_id,
video.get('screen_video_path'),
video.get('femtobolt_video_path'),
video.get('camera1_video_path'),
video.get('camera2_video_path'),
china_time
))

File diff suppressed because it is too large Load Diff

View File

@ -228,34 +228,13 @@ class AppServer:
self.device_coordinator = DeviceCoordinator(self.socketio)
# 设置状态变化回调
self.device_coordinator.set_status_change_callback(self._on_device_status_change)
# 调用初始化方法来初始化设备
if self.device_coordinator.initialize():
self.logger.info('设备协调器初始化完成')
# 获取设备管理器实例
self.device_managers = self.device_coordinator.get_device_managers()
# 为每个设备添加状态变化回调(双重保险)
for device_name, manager in self.device_managers.items():
if manager and hasattr(manager, 'add_status_change_callback'):
manager.add_status_change_callback(self._on_device_status_change)
self.logger.info(f'已获取设备管理器: {list(self.device_managers.keys())}')
else:
self.logger.warning('设备协调器初始化失败,但系统将继续运行')
self.device_managers = {} # 初始化为空字典以避免后续错误
# 设备初始化现在延迟到用户登录成功后进行,加快启动速度
# 初始化录制管理器
self.logger.info('正在初始化录制管理器...')
femtobolt_manager = self.device_managers.get('femtobolt')
pressure_manager = self.device_managers.get('pressure')
# 录制管理器当前采用屏幕区域截取方式进行相机录制,不依赖 CameraManager
# 但保留其他设备管理器以便后续扩展如FemtoBolt、压力传感器
# 录制管理器
self.recording_manager = RecordingManager(
camera_manager=None,
db_manager=self.db_manager,
femtobolt_manager=femtobolt_manager,
pressure_manager=pressure_manager,
config_manager=self.config_manager
)
self.logger.info('录制管理器初始化完成')
@ -276,6 +255,29 @@ class AppServer:
self.logger.error(f'应用初始化失败: {e}')
raise
def _initialize_devices(self):
"""
初始化设备在用户登录成功后调用
"""
try:
self.logger.info('开始初始化设备...')
if self.device_coordinator.initialize():
self.logger.info('设备协调器初始化完成')
# 获取设备管理器实例
self.device_managers = self.device_coordinator.get_device_managers()
# 为每个设备添加状态变化回调(双重保险)
for device_name, manager in self.device_managers.items():
if manager and hasattr(manager, 'add_status_change_callback'):
manager.add_status_change_callback(self._on_device_status_change)
self.logger.info(f'已获取设备管理器: {list(self.device_managers.keys())}')
else:
self.logger.warning('设备协调器初始化失败,但系统将继续运行')
self.device_managers = {} # 初始化为空字典以避免后续错误
except Exception as e:
self.logger.error(f'设备初始化异常: {e}')
def require_license(self, feature=None):
"""
授权检查装饰器
@ -755,6 +757,10 @@ class AppServer:
self.logger.info(f'用户 {username} 登录成功')
# 登录成功后,异步初始化设备(如果尚未初始化)
if self.device_coordinator and not self.device_coordinator.is_initialized:
threading.Thread(target=self._initialize_devices, daemon=True).start()
return jsonify({
'success': True,
'data': {
@ -1220,8 +1226,6 @@ class AppServer:
}), 400
result = self.config_manager.set_all_device_configs(data)
status_code = 200 if result['success'] else 400
return jsonify(result), status_code
@ -1282,6 +1286,17 @@ class AppServer:
if not self.db_manager or not self.device_coordinator:
return jsonify({'success': False, 'error': '数据库管理器或设备管理器未初始化'}), 500
# 检查设备是否已初始化
if self.device_coordinator and not self.device_coordinator.is_initialized:
self.logger.info('设备尚未初始化,等待初始化完成...')
# 最多等待10秒
start_wait = time.time()
while not self.device_coordinator.is_initialized:
if time.time() - start_wait > 10:
return jsonify({'success': False, 'error': '设备初始化超时,请稍后重试'}), 503
time.sleep(0.5)
self.logger.info('设备初始化完成,继续开始检测')
data = flask_request.get_json()
patient_id = data.get('patient_id')
creator_id = data.get('creator_id')
@ -1324,7 +1339,6 @@ class AppServer:
try:
if not self.db_manager:
return jsonify({'success': False, 'error': '数据库管理器未初始化'}), 500
# 获取检测数据和视频数据
session_data = self.db_manager.get_session_data(session_id)
if not session_data:
@ -1418,16 +1432,14 @@ class AppServer:
data = flask_request.get_json()
patient_id = data.get('patient_id')
screen_location = data.get('screen_location') # [0,0,1920,1080]
femtobolt_location = data.get('femtobolt_location') # [0,0,640,480]
camera1_location = data.get('camera1_location') # [0,0,640,480]
camera2_location = data.get('camera2_location') # [0,0,640,480]
if not patient_id:
return jsonify({'success': False, 'error': '缺少患者ID'}), 400
# 开始视频录制
recording_response = None
try:
recording_response = self.recording_manager.start_recording(session_id, patient_id,screen_location,camera1_location,camera2_location,femtobolt_location)
# 使用新的ffmpeg录制方法
recording_response = self.recording_manager.start_recording_ffmpeg(session_id, patient_id, screen_location)
# 处理录制管理器返回的数据库更新信息
if recording_response and recording_response.get('success') and 'database_updates' in recording_response:
@ -1436,10 +1448,7 @@ class AppServer:
# 保存检测视频记录(映射到 detection_video 表字段)
video_paths = db_updates.get('video_paths', {})
video_record = {
'screen_video_path': video_paths.get('screen_video_path'),
'femtobolt_video_path': video_paths.get('femtobolt_video_path'),
'camera1_video_path': video_paths.get('camera1_video_path'),
'camera2_video_path': video_paths.get('camera2_video_path'),
'screen_video_path': video_paths.get('screen_video_path')
}
try:
@ -1473,7 +1482,7 @@ class AppServer:
}), 400
# 停止同步录制,传递视频数据
try:
restrt = self.recording_manager.stop_recording(session_id)
restrt = self.recording_manager.stop_recording_ffmpeg(session_id)
self.logger.info(f'停止录制结果: {restrt}')
except Exception as rec_e:
self.logger.error(f'停止同步录制失败: {rec_e}', exc_info=True)

View File

@ -91,10 +91,10 @@ router.beforeEach(async (to, from, next) => {
}
// 如果已登录用户访问登录页,重定向到仪表板
if (to.name === 'Login' && authStore.isAuthenticated) {
next({ name: 'Dashboard' })
return
}
// if (to.name === 'Login' && authStore.isAuthenticated) {
// next({ name: 'Dashboard' })
// return
// }
next()
})

View File

@ -5,8 +5,8 @@ import { authAPI } from '../services/api'
// 认证状态管理
export const useAuthStore = defineStore('auth', () => {
// 状态
const authToken = ref(localStorage.getItem('authToken') || null)
const currentUser = ref(JSON.parse(localStorage.getItem('currentUser') || 'null'))
const authToken = ref(sessionStorage.getItem('authToken') || null)
const currentUser = ref(JSON.parse(sessionStorage.getItem('currentUser') || 'null'))
const isLoading = ref(false)
const error = ref(null)
@ -25,9 +25,9 @@ export const useAuthStore = defineStore('auth', () => {
authToken.value = token
currentUser.value = user
// 保存到本地存储
localStorage.setItem('authToken', token)
localStorage.setItem('currentUser', JSON.stringify(user))
// 保存到会话存储(关闭浏览器/应用后失效)
sessionStorage.setItem('authToken', token)
sessionStorage.setItem('currentUser', JSON.stringify(user))
return { success: true, data: response.data }
} catch (err) {
@ -79,8 +79,8 @@ export const useAuthStore = defineStore('auth', () => {
// 清除本地状态
authToken.value = null
currentUser.value = null
localStorage.removeItem('authToken')
localStorage.removeItem('currentUser')
sessionStorage.removeItem('authToken')
sessionStorage.removeItem('currentUser')
}
}

View File

@ -14,7 +14,10 @@
<div v-for="(item, index) in useImgList" :key="index"
class="PhotoAlbum-imgbox">
<div class="PhotoAlbum-imgactive" @click="clickImg(item,index)">
<img :src="BACKEND_URL+'/' + item.screen_image" alt="" style="width: 100%;height: 100%;">
<img v-if="item.type == 'data'" :src="BACKEND_URL+'/' + item.screen_image" alt="" style="width: 100%;height: 100%;">
<video v-else-if="item.type == 'video'" :src="item.screen_video ? BACKEND_URL+'/' + item.screen_video.replace(/\\/g, '/') : ''" controls width="100%" height="100%">
您的浏览器不支持视频播放
</video>
</div>
<div class="PhotoAlbum-imgtextbox">
<el-checkbox
@ -111,7 +114,7 @@ async function tipConfirm(){
if(elements.type == 'data'){
imgIds.push(elements.id)
}
if(elements.type == 'videos'){
if(elements.type == 'video'){
videoIds.push(elements.id)
}