const { app, BrowserWindow } = require('electron'); const path = require('path'); const http = require('http'); const fs = require('fs'); const url = require('url'); const { spawn } = require('child_process'); let mainWindow; let localServer; let backendProcess; function startBackendService() { // 在打包后的应用中,使用process.resourcesPath获取resources目录 const resourcesPath = process.resourcesPath || path.join(__dirname, '../..'); const backendPath = path.join(resourcesPath, 'backend/BodyBalanceBackend/BodyBalanceBackend.exe'); const backendDir = path.join(resourcesPath, 'backend/'); console.log('Resources path:', resourcesPath); console.log('Backend path:', backendPath); console.log('Backend directory:', backendDir); // 检查后端可执行文件是否存在 if (!fs.existsSync(backendPath)) { console.error('Backend executable not found:', backendPath); // 尝试备用路径 const fallbackPath = path.join(__dirname, 'resources/backend/BodyBalanceBackend/BodyBalanceBackend.exe'); console.log('Trying fallback path:', fallbackPath); if (!fs.existsSync(fallbackPath)) { console.error('Fallback backend executable not found:', fallbackPath); return; } // 使用备用路径 const fallbackDir = path.join(__dirname, 'resources/backend/BodyBalanceBackend/'); backendProcess = spawn(fallbackPath, [], { cwd: fallbackDir, stdio: ['ignore', 'pipe', 'pipe'] }); console.log('Starting backend service with fallback path:', fallbackPath); } else { console.log('Starting backend service:', backendPath); // 启动后端进程 backendProcess = spawn(backendPath, [], { cwd: backendDir, stdio: ['ignore', 'pipe', 'pipe'] }); } backendProcess.stdout.on('data', (data) => { console.log('Backend stdout:', data.toString()); }); backendProcess.stderr.on('data', (data) => { console.error('Backend stderr:', data.toString()); }); backendProcess.on('close', (code) => { console.log('Backend process exited with code:', code); backendProcess = null; }); backendProcess.on('error', (err) => { console.error('Failed to start backend process:', err); backendProcess = null; }); } function stopBackendService() { if (backendProcess) { console.log('Stopping backend service...'); backendProcess.kill('SIGTERM'); backendProcess = null; } // 强制杀死所有BodyBalanceBackend.exe进程 try { const { exec } = require('child_process'); exec('taskkill /f /im BodyBalanceBackend.exe', (error, stdout, stderr) => { if (error) { // 如果没有找到进程,taskkill会返回错误,这是正常的 if (!error.message.includes('not found')) { console.error('Error killing BodyBalanceBackend processes:', error.message); } } else { console.log('Successfully killed all BodyBalanceBackend processes:', stdout); } }); } catch (err) { console.error('Failed to execute taskkill command:', err); } } function createWindow() { mainWindow = new BrowserWindow({ width: 1920, height: 1080, webPreferences: { nodeIntegration: false, contextIsolation: true, preload: path.join(__dirname, 'preload.js') }, icon: path.join(__dirname, '../../assets/icon.ico'), show: false, fullscreen: false, frame: true, autoHideMenuBar: true, backgroundColor: '#000000' }); // 窗口创建后立即最大化 mainWindow.maximize(); // 开发环境加载本地服务器,生产环境加载打包后的文件 const isDev = process.env.NODE_ENV === 'development'; if (isDev) { mainWindow.loadURL('http://localhost:3000'); // mainWindow.webContents.openDevTools(); // 如需调试,请手动打开或在 did-finish-load 之后打开 } else { // 启动后端服务 startBackendService(); // 延迟1秒后启动本地HTTP服务器 setTimeout(() => { startLocalServer(() => { mainWindow.loadURL('http://localhost:3000'); }); }, 1000); } // 窗口就绪后再显示,避免白屏/闪烁 mainWindow.once('ready-to-show', () => { mainWindow.show(); }); // 监听页面加载完成事件 mainWindow.webContents.once('did-finish-load', () => { console.log('Page loaded completely'); }); // 添加加载失败的处理 mainWindow.webContents.on('did-fail-load', (event, errorCode, errorDescription, validatedURL) => { console.log('Failed to load:', errorDescription, 'URL:', validatedURL); mainWindow.show(); // 即使加载失败也显示窗口 }); mainWindow.on('closed', () => { mainWindow = null; if (localServer) { localServer.close(); } // 关闭后端服务 stopBackendService(); }); } function startLocalServer(callback) { const staticPath = path.join(__dirname, '../dist/'); localServer = http.createServer((req, res) => { const parsedUrl = url.parse(req.url); let pathname = parsedUrl.pathname; // 默认加载index.html if (pathname === '/') { pathname = '/index.html'; } const filePath = path.join(staticPath, pathname); fs.readFile(filePath, (err, data) => { if (err) { res.writeHead(404, { 'Content-Type': 'text/plain' }); res.end('File not found'); return; } // 设置正确的Content-Type const ext = path.extname(filePath); let contentType = 'text/html'; switch (ext) { case '.js': contentType = 'application/javascript'; break; case '.css': contentType = 'text/css'; break; case '.json': contentType = 'application/json'; break; case '.png': contentType = 'image/png'; break; case '.jpg': case '.jpeg': contentType = 'image/jpeg'; break; case '.svg': contentType = 'image/svg+xml'; break; } res.writeHead(200, { 'Content-Type': contentType }); res.end(data); }); }); localServer.listen(3000, 'localhost', () => { console.log('Local server started on http://localhost:3000'); callback(); }); } // 应用事件处理 // 关闭硬件加速以规避 GPU 进程异常导致的闪烁 app.disableHardwareAcceleration(); app.whenReady().then(createWindow); app.on('window-all-closed', () => { if (process.platform !== 'darwin') { if (localServer) { localServer.close(); } // 关闭后端服务 stopBackendService(); app.quit(); } }); app.on('activate', () => { if (BrowserWindow.getAllWindows().length === 0) { createWindow(); } }); // 应用退出前清理资源 app.on('before-quit', () => { stopBackendService(); });