const { app, BrowserWindow, ipcMain, Menu } = require('electron'); const path = require('path'); const { spawn } = require('child_process'); const dotenv = require('dotenv'); const fs = require('fs'); // 加载环境变量 const envPath = path.join(__dirname, '..', '.env'); if (fs.existsSync(envPath)) { dotenv.config({ path: envPath }); } let mainWindow; let backendProcess; /** * 创建Electron主窗口 */ function createWindow() { mainWindow = new BrowserWindow({ width: 1200, height: 800, webPreferences: { preload: path.join(__dirname, 'preload.js'), nodeIntegration: false, contextIsolation: true, }, autoHideMenuBar: false, title: '投标应用', }); // 加载前端页面 const indexPath = path.join(__dirname, '..', 'frontend', 'dist', 'index.html'); mainWindow.loadFile(indexPath); // 开发环境下打开开发者工具 if (process.env.NODE_ENV === 'development') { mainWindow.webContents.openDevTools(); // 过滤掉 DevTools 的 Autofill 相关错误 mainWindow.webContents.on('console-message', (event, level, message, line, sourceId) => { if (message.includes('Autofill.enable') || message.includes('Autofill.setAddresses')) { event.preventDefault(); } }); } mainWindow.on('closed', () => { mainWindow = null; }); } /** * 等待后端服务启动 */ function waitForBackend(port = 3000, maxRetries = 30, interval = 1000) { return new Promise((resolve, reject) => { let retries = 0; const checkBackend = () => { const net = require('net'); const client = new net.Socket(); client.once('connect', () => { client.destroy(); console.log('后端服务已启动'); resolve(); }); client.once('error', () => { client.destroy(); retry(); }); client.once('timeout', () => { client.destroy(); retry(); }); client.connect(port, 'localhost'); client.setTimeout(1000); function retry() { retries++; if (retries >= maxRetries) { reject(new Error('后端服务启动超时')); } else { console.log(`等待后端服务启动... (${retries}/${maxRetries})`); setTimeout(checkBackend, interval); } } }; checkBackend(); }); } /** * 启动后端服务 */ async function startBackend() { let backendPath; if (process.resourcesPath) { // 生产环境:使用 app.asar.unpacked 中的文件 backendPath = path.join(process.resourcesPath, 'app.asar.unpacked', 'dist', 'main.js'); } else { // 开发环境 backendPath = path.join(__dirname, '..', 'dist', 'main.js'); } // 检查后端构建文件是否存在 if (!fs.existsSync(backendPath)) { console.error('后端服务构建文件不存在,路径:', backendPath); console.error('请先执行 npm run build'); return; } console.log('启动后端服务:', backendPath); // 启动后端服务 backendProcess = spawn('node', [backendPath], { env: { ...process.env, NODE_ENV: process.env.NODE_ENV || 'production', }, stdio: 'pipe', }); backendProcess.on('error', (error) => { console.error('后端服务启动失败:', error); }); backendProcess.on('exit', (code) => { console.log(`后端服务退出,退出码: ${code}`); backendProcess = null; }); // 等待后端服务启动完成 try { await waitForBackend(); } catch (error) { console.error('等待后端服务启动失败:', error.message); } } /** * 停止后端服务 */ function stopBackend() { if (backendProcess) { console.log('正在停止后端服务...'); backendProcess.kill(); backendProcess = null; } } // 应用就绪时启动后端服务,然后创建窗口 app.on('ready', async () => { await startBackend(); createWindow(); Menu.setApplicationMenu(null); }); // 所有窗口关闭时退出应用 app.on('window-all-closed', () => { stopBackend(); if (process.platform !== 'darwin') { app.quit(); } }); // MacOS上点击dock图标时重新创建窗口 app.on('activate', async () => { if (BrowserWindow.getAllWindows().length === 0) { if (!backendProcess) { await startBackend(); } createWindow(); } }); // 应用退出前停止后端服务 app.on('before-quit', () => { stopBackend(); }); // 处理来自渲染进程的IPC消息 ipcMain.handle('get-env', (event, key) => { return process.env[key]; });