main.js 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. // main.js (ESM 版本)
  2. import { app, BrowserWindow, Menu, ipcMain, shell } from 'electron';
  3. import { fileURLToPath } from 'url';
  4. import { dirname, join } from 'path';
  5. import { exec } from 'child_process';
  6. import { promisify } from 'util';
  7. import { writeLog } from './src/log/log-writer.js';
  8. // -------------- 构造 ESM 版 __dirname --------------
  9. const __filename = fileURLToPath(import.meta.url);
  10. const __dirname = dirname(__filename);
  11. const execAsync = promisify(exec);
  12. // -------------- 创建窗口 --------------
  13. function createWindow() {
  14. const isMac = process.platform === 'darwin';
  15. const win = new BrowserWindow({
  16. show: false,
  17. frame: false,
  18. titleBarStyle: 'hidden',
  19. webPreferences: {
  20. nodeIntegration: false,
  21. contextIsolation: true,
  22. preload: join(__dirname, 'preload.js'),
  23. },
  24. });
  25. // 去掉应用菜单栏
  26. Menu.setApplicationMenu(null);
  27. if (!isMac) win.removeMenu();
  28. win.maximize();
  29. // 加载外置 H5 页面
  30. win.loadFile(join(process.cwd(), 'h5/index.html'));
  31. win.once('ready-to-show', () => win.show());
  32. //渲染进程死了,纪录日志
  33. win.webContents.on('render-process-gone', (event, details) => {
  34. writeLog('error',`渲染进程崩溃 ${details}`);
  35. // writeLog('error', JSON.stringify(details));
  36. });
  37. }
  38. // -------------- 应用生命周期 --------------
  39. app.whenReady().then(createWindow);
  40. app.on('window-all-closed', () => {
  41. if (process.platform !== 'darwin') app.quit();
  42. });
  43. app.on('activate', () => {
  44. if (BrowserWindow.getAllWindows().length === 0) createWindow();
  45. });
  46. // -------------- 系统操作函数 --------------
  47. const getSystemCommands = () => {
  48. const platform = process.platform;
  49. switch (platform) {
  50. case 'win32': // Windows
  51. return {
  52. shutdown: 'shutdown /s /t 0'
  53. };
  54. case 'darwin': // macOS
  55. return {
  56. shutdown: 'sudo shutdown -h now'
  57. };
  58. case 'linux': // Linux
  59. return {
  60. shutdown: 'systemctl poweroff'
  61. };
  62. default:
  63. return {
  64. shutdown: null
  65. };
  66. }
  67. };
  68. const executeSystemCommand = async (command, requiresAdmin = false) => {
  69. try {
  70. if (!command) {
  71. throw new Error('当前平台不支持该操作');
  72. }
  73. // Windows平台的权限检查
  74. if (process.platform === 'win32' && requiresAdmin) {
  75. // 检查是否以管理员身份运行
  76. try {
  77. await execAsync('net session', { timeout: 5000 });
  78. } catch (adminCheckError) {
  79. writeLog('warn', '操作可能需要管理员权限');
  80. return {
  81. success: false,
  82. error: '该操作需要管理员权限,请以管理员身份运行程序后重试',
  83. requiresAdmin: true
  84. };
  85. }
  86. }
  87. const { stdout, stderr } = await execAsync(command, { timeout: 10000 });
  88. writeLog('info', `系统命令执行成功: ${command}`);
  89. if (stderr && stderr.trim()) {
  90. writeLog('warn', `系统命令有警告信息: ${stderr}`);
  91. }
  92. return { success: true, stdout, stderr };
  93. } catch (error) {
  94. let errorMessage = error.message;
  95. // 特定错误类型的处理
  96. if (error.code === 'EACCES') {
  97. errorMessage = '权限不足,请以管理员身份运行程序';
  98. } else if (error.code === 'ENOENT') {
  99. errorMessage = '系统命令不存在或路径错误';
  100. } else if (error.code === 'ETIMEDOUT') {
  101. errorMessage = '操作超时,请重试';
  102. }
  103. writeLog('error', `系统命令执行失败: ${command}, 错误: ${errorMessage}`);
  104. return { success: false, error: errorMessage };
  105. }
  106. };
  107. // -------------- IPC --------------
  108. ipcMain.handle('write-log', async (_, level, msg) => {
  109. writeLog(level, msg);
  110. });
  111. // 退出应用
  112. ipcMain.handle('exit-close', async () => {
  113. writeLog('info', '用户选择关闭应用程序');
  114. app.quit();
  115. return { success: true };
  116. });
  117. // 关机
  118. ipcMain.handle('exit-shutdown', async () => {
  119. writeLog('info', '用户选择关机');
  120. const commands = getSystemCommands();
  121. // 关机通常需要管理员权限
  122. const requiresAdmin = true;
  123. return await executeSystemCommand(commands.shutdown, requiresAdmin);
  124. });