237 lines
6.6 KiB
JavaScript
237 lines
6.6 KiB
JavaScript
|
|
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.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.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/');
|
|||
|
|
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'
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 开发环境加载本地服务器,生产环境加载打包后的文件
|
|||
|
|
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();
|
|||
|
|
});
|