// 主进程:创建窗口、启动后端 JAR、隐藏菜单栏 import {app, BrowserWindow, ipcMain, session, Menu, screen} from 'electron'; import { Socket } from 'net'; import { existsSync } from 'fs'; import {join, dirname} from 'path'; import {spawn, ChildProcessWithoutNullStreams} from 'child_process'; // 保存后端进程与窗口引用,便于退出时清理 let springProcess: ChildProcessWithoutNullStreams | null = null; let mainWindow: BrowserWindow | null = null; let splashWindow: BrowserWindow | null = null; let appOpened = false; function openAppIfNotOpened() { if (appOpened) return; appOpened = true; if (mainWindow) { mainWindow.show(); mainWindow.focus(); } if (splashWindow) { splashWindow.close(); splashWindow = null; } } // 启动后端 Spring Boot(使用你提供的绝对路径) function startSpringBoot() { const jarPath = 'C:/Users/ZiJIe/Desktop/wox/RuoYi-Vue/ruoyi-admin/target/ruoyi-admin.jar'; springProcess = spawn('java', ['-jar', jarPath], { cwd: dirname(jarPath), detached: false }); // 打印后端日志,监听启动成功标志 springProcess.stdout.on('data', (data) => { console.log(`SpringBoot: ${data}`); // 检测到启动成功日志立即进入主界面 if (data.toString().includes('Started RuoYiApplication')) { openAppIfNotOpened(); } }); // 打印后端错误,检测启动失败 springProcess.stderr.on('data', (data) => { console.error(`SpringBoot ERROR: ${data}`); const errorStr = data.toString(); // 检测到关键错误信息,直接退出 if (errorStr.includes('APPLICATION FAILED TO START') || errorStr.includes('Port') && errorStr.includes('already in use') || errorStr.includes('Unable to start embedded Tomcat')) { console.error('后端启动失败,程序即将退出'); app.quit(); } }); // 后端退出时,前端同步退出 springProcess.on('close', (code) => { console.log(`SpringBoot exited with code ${code}`); if (mainWindow) { mainWindow.close(); } else { app.quit(); } }); } // 关闭后端进程(Windows 使用 taskkill 结束整个进程树) function stopSpringBoot() { if (!springProcess) return; try { if (process.platform === 'win32') { // Force kill the whole process tree on Windows try { const pid = springProcess.pid; if (pid !== undefined && pid !== null) { spawn('taskkill', ['/pid', String(pid), '/f', '/t']); } else { springProcess.kill(); } } catch (e) { // Fallback springProcess.kill(); } } else { springProcess.kill('SIGTERM'); } } catch (e) { console.error('Failed to stop Spring Boot process:', e); } finally { springProcess = null; } } function createWindow () { mainWindow = new BrowserWindow({ width: 1280, height: 800, show: false, autoHideMenuBar: true, icon: join(__dirname, '../renderer/icon/icon.png'), // 添加窗口图标 webPreferences: { preload: join(__dirname, 'preload.js'), nodeIntegration: false, contextIsolation: true, } }); // 彻底隐藏原生菜单栏 try { Menu.setApplicationMenu(null); mainWindow.setMenuBarVisibility(false); if (typeof (mainWindow as any).setMenu === 'function') { (mainWindow as any).setMenu(null); } } catch {} // 生产环境加载本地文件 if (process.env.NODE_ENV === 'development') { const rendererPort = process.argv[2] || 8083; mainWindow.loadURL(`http://localhost:${rendererPort}`); } else { mainWindow.loadFile(join(__dirname, '../renderer/index.html')); } } app.whenReady().then(() => { // 预创建主窗口(隐藏) createWindow(); // 显示启动页 const { width: sw, height: sh } = screen.getPrimaryDisplay().workAreaSize; const splashW = Math.min(Math.floor(sw * 0.8), 1800); const splashH = Math.min(Math.floor(sh * 0.8), 1200); splashWindow = new BrowserWindow({ width: splashW, height: splashH, frame: false, transparent: false, resizable: false, alwaysOnTop: true, show: true, center: true, }); const candidateSplashPaths = [ join(__dirname, '../../public', 'splash.html'), ]; const foundSplash = candidateSplashPaths.find(p => existsSync(p)); if (foundSplash) { splashWindow.loadFile(foundSplash); } // 注释掉后端启动,便于快速调试前端 // startSpringBoot(); // 快速调试模式 - 直接打开主窗口 setTimeout(() => { openAppIfNotOpened(); }, 1000); app.on('activate', function () { // On macOS it's common to re-create a window in the app when the // dock icon is clicked and there are no other windows open. if (BrowserWindow.getAllWindows().length === 0) { createWindow(); } }); }); app.on('window-all-closed', function () { stopSpringBoot(); if (process.platform !== 'darwin') app.quit() }); app.on('before-quit', () => { stopSpringBoot(); }); ipcMain.on('message', (event, message) => { console.log(message); })