diff --git a/backend/devices/camera_manager.py b/backend/devices/camera_manager.py index 220ba2c7..a3279274 100644 --- a/backend/devices/camera_manager.py +++ b/backend/devices/camera_manager.py @@ -154,6 +154,19 @@ class CameraManager(BaseDevice): return True + def set_connected(self, is_connected: bool): + """ + 设置连接状态并触发回调 + + Args: + is_connected: 连接状态 + """ + # 更新心跳时间,防止刚连接就被判定超时 + if is_connected: + self.update_heartbeat() + + super().set_connected(is_connected) + def initialize(self) -> bool: """ 初始化相机设备 @@ -222,6 +235,8 @@ class CameraManager(BaseDevice): # 使用set_connected方法来正确启动连接监控线程 self.set_connected(True) self._last_connected_state = True + # 更新心跳时间,防止连接监控线程刚启动就判定为超时 + self.update_heartbeat() self._device_info.update({ 'device_index': self.device_index, 'resolution': f"{self.width}x{self.height}", @@ -493,6 +508,8 @@ class CameraManager(BaseDevice): try: self.is_streaming = True + # 更新心跳时间,确保流开始时不会被误判超时 + self.update_heartbeat() self.streaming_thread = threading.Thread( target=self._streaming_worker, name=f"Camera-{self.device_index}-Stream", @@ -919,7 +936,7 @@ class CameraManager(BaseDevice): """ try: if not self.is_connected: - self.logger.info("相机未连接,检查连接状态") + # self.logger.info("相机未连接,检查连接状态") return False # 尝试读取一帧 @@ -928,7 +945,7 @@ class CameraManager(BaseDevice): self.logger.error("相机连接已断开,读取失败") return False - self.logger.info("相机硬件连接正常") + # self.logger.info("相机硬件连接正常") return True except Exception as e: diff --git a/backend/main.py b/backend/main.py index bc578acc..c9683f64 100644 --- a/backend/main.py +++ b/backend/main.py @@ -86,7 +86,8 @@ class AppServer: self.config_manager = None self.device_coordinator = None self.device_managers = { - 'camera': None, + 'camera1': None, + 'camera2': None, 'femtobolt': None, 'imu': None, 'pressure': None, @@ -167,7 +168,7 @@ class AppServer: self.config.read(config_path, encoding='utf-8') camera1_index = self.config.get('CAMERA1', 'device_index', fallback=None) camera2_index = self.config.get('CAMERA2', 'device_index', fallback=None) - print(f"相机1设备号: {camera1_index}, 相机2设备号: {camera2_index}") + def init_app(self): """初始化应用组件""" @@ -225,10 +226,7 @@ class AppServer: # 初始化设备协调器(统一管理所有设备) self.logger.info('正在初始化设备协调器...') - self.device_coordinator = DeviceCoordinator(self.socketio) - # 设置状态变化回调 - self.device_coordinator.set_status_change_callback(self._on_device_status_change) - # 设备初始化现在延迟到用户登录成功后进行,加快启动速度 + self.device_coordinator = DeviceCoordinator(self.socketio) # 初始化录制管理器 self.logger.info('正在初始化录制管理器...') @@ -1876,7 +1874,23 @@ class AppServer: emit('status', {'message': '设备命名空间连接成功'}, namespace='/devices') # 连接时发送当前所有设备的状态 - self.broadcast_all_device_status() + try: + if self.device_coordinator and getattr(self.device_coordinator, 'is_initialized', False): + self.broadcast_all_device_status() + else: + def _delayed_broadcast(): + start_ts = time.time() + while self.device_coordinator and not getattr(self.device_coordinator, 'is_initialized', False): + if time.time() - start_ts > 15: + return + time.sleep(0.2) + try: + self.broadcast_all_device_status() + except Exception: + pass + threading.Thread(target=_delayed_broadcast, daemon=True).start() + except Exception: + pass @self.socketio.on('disconnect', namespace='/devices') def handle_devices_disconnect(): @@ -1941,7 +1955,7 @@ class AppServer: """重启指定类型的设备 Args: - device_type (str): 设备类型 (camera, imu, pressure, femtobolt) + device_type (str): 设备类型 (camera1, camera2, femtobolt, imu, pressure, remote) """ if not self.device_coordinator: self.logger.error('设备协调器未初始化,无法重启设备') @@ -1994,6 +2008,11 @@ class AppServer: return try: + if self.device_coordinator and not getattr(self.device_coordinator, 'is_initialized', False): + self._initialize_devices() + if self.device_coordinator: + self.device_managers = self.device_coordinator.get_device_managers() + self.logger.info('开始设备数据推送...') self.is_pushing_data = True diff --git a/frontend/src/renderer/main/main.js b/frontend/src/renderer/main/main.js index dcfd2645..98f68ba7 100644 --- a/frontend/src/renderer/main/main.js +++ b/frontend/src/renderer/main/main.js @@ -15,6 +15,19 @@ ipcMain.handle('generate-report-pdf', async (event, payload) => { const win = BrowserWindow.fromWebContents(event.sender); if (!win) throw new Error('窗口未找到'); + let prevWinBg = null; + try { + if (typeof win.getBackgroundColor === 'function') { + prevWinBg = win.getBackgroundColor(); + } + if (typeof win.setBackgroundColor === 'function') { + win.setBackgroundColor('#FFFFFFFF'); + } + if (win.webContents && typeof win.webContents.setBackgroundColor === 'function') { + win.webContents.setBackgroundColor('#FFFFFFFF'); + } + } catch (e) {} + // 1. 准备打印环境:克隆节点到独立的打印容器,确保流式布局 await win.webContents.executeJavaScript(` (function(){ @@ -61,17 +74,23 @@ ipcMain.handle('generate-report-pdf', async (event, payload) => { style.id = 'print-style-override'; style.innerHTML = \` @media print { + html, body { + background: #ffffff !important; + margin: 0 !important; + padding: 0 !important; + -webkit-print-color-adjust: exact; + print-color-adjust: exact; + } body > *:not(#electron-print-container) { display: none !important; } #electron-print-container { display: block !important; + background: #ffffff !important; } } \`; document.head.appendChild(style); - - document.body.classList.add('print-mode'); return true; })() @@ -86,7 +105,7 @@ ipcMain.handle('generate-report-pdf', async (event, payload) => { displayHeaderFooter: true, // 启用页眉页脚 headerTemplate: '
', // 空页眉 footerTemplate: ` -
+
页 / 共
` @@ -98,10 +117,19 @@ ipcMain.handle('generate-report-pdf', async (event, payload) => { (function(){ const container = document.getElementById('electron-print-container'); if (container) container.remove(); - document.body.classList.remove('print-mode'); + const style = document.getElementById('print-style-override'); + if (style) style.remove(); return true; })() `); + try { + if (prevWinBg && typeof win.setBackgroundColor === 'function') { + win.setBackgroundColor(prevWinBg); + } + if (prevWinBg && win.webContents && typeof win.webContents.setBackgroundColor === 'function') { + win.webContents.setBackgroundColor(prevWinBg); + } + } catch (e) {} } }); diff --git a/frontend/src/renderer/src/report_212121965.pdf b/frontend/src/renderer/src/report_212121965.pdf new file mode 100644 index 00000000..5a4213be Binary files /dev/null and b/frontend/src/renderer/src/report_212121965.pdf differ diff --git a/frontend/src/renderer/src/services/api.js b/frontend/src/renderer/src/services/api.js index 494b282b..14992bd1 100644 --- a/frontend/src/renderer/src/services/api.js +++ b/frontend/src/renderer/src/services/api.js @@ -25,7 +25,7 @@ api.interceptors.request.use( } // 添加认证token - const token = localStorage.getItem('authToken') + const token = sessionStorage.getItem('authToken') if (token) { config.headers['Authorization'] = `Bearer ${token}` } diff --git a/frontend/src/renderer/src/views/PhotoAlbum.vue b/frontend/src/renderer/src/views/PhotoAlbum.vue index 83dffb66..68bfefe0 100644 --- a/frontend/src/renderer/src/views/PhotoAlbum.vue +++ b/frontend/src/renderer/src/views/PhotoAlbum.vue @@ -13,8 +13,8 @@ justify-content: start;">
-
- +
+ @@ -216,7 +216,7 @@ onMounted(() => { height: calc(100% - 160px); /* background: red; */ margin-top: 20px; - padding:0px 52px; + padding:0px 48px; display: flex; flex-wrap:wrap ; align-content: flex-start;