183 lines
5.5 KiB
TypeScript
183 lines
5.5 KiB
TypeScript
// 主进程:创建窗口、启动后端 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);
|
||
}) |