修正了main设备初始化顺序、pdf黑白bug、桌面快捷图标bug

This commit is contained in:
root 2026-01-11 21:50:12 +08:00
parent 685765e2b2
commit 5ed15ce017
6 changed files with 82 additions and 18 deletions

View File

@ -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:

View File

@ -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):
"""初始化应用组件"""
@ -226,9 +227,6 @@ class AppServer:
# 初始化设备协调器(统一管理所有设备)
self.logger.info('正在初始化设备协调器...')
self.device_coordinator = DeviceCoordinator(self.socketio)
# 设置状态变化回调
self.device_coordinator.set_status_change_callback(self._on_device_status_change)
# 设备初始化现在延迟到用户登录成功后进行,加快启动速度
# 初始化录制管理器
self.logger.info('正在初始化录制管理器...')
@ -1876,7 +1874,23 @@ class AppServer:
emit('status', {'message': '设备命名空间连接成功'}, namespace='/devices')
# 连接时发送当前所有设备的状态
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

View File

@ -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,18 +74,24 @@ 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: '<div></div>', // 空页眉
footerTemplate: `
<div style="width: 100%; text-align: center; font-size: 10px; font-family: 'Microsoft YaHei', sans-serif; padding-top: 5px; padding-bottom: 5px;">
<div style="width: 100%; text-align: center; font-size: 10px; font-family: 'Microsoft YaHei', sans-serif; padding-top: 5px; padding-bottom: 5px; background: #ffffff;">
<span class="pageNumber"></span> 页 / <span class="totalPages"></span>
</div>
`
@ -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) {}
}
});

Binary file not shown.

View File

@ -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}`
}

View File

@ -13,8 +13,8 @@
justify-content: start;">
<div v-for="(item, index) in useImgList" :key="index"
class="PhotoAlbum-imgbox">
<div class="PhotoAlbum-imgactive" @click="clickImg(item,index)">
<img v-if="item.type == 'data'" :src="BACKEND_URL+'/' + item.screen_image" alt="" style="width: 100%;height: 100%;">
<div class="PhotoAlbum-imgactive" >
<img v-if="item.type == 'data'" :src="BACKEND_URL+'/' + item.screen_image" alt="" style="width: 100%;height: 100%;" @click="clickImg(item,index)">
<video v-else-if="item.type == 'video'" :src="item.screen_video ? BACKEND_URL+'/' + item.screen_video.replace(/\\/g, '/') : ''" controls width="100%" height="100%">
您的浏览器不支持视频播放
</video>
@ -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;