main.js 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  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: !isMac,
  18. titleBarStyle: isMac ? 'hiddenInset' : 'default',
  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. logout: 'shutdown /l',
  53. shutdown: 'shutdown /s /t 0'
  54. };
  55. case 'darwin': // macOS
  56. return {
  57. logout: 'sudo launchctl bootout gui/$(id -u)',
  58. shutdown: 'sudo shutdown -h now'
  59. };
  60. case 'linux': // Linux
  61. return {
  62. logout: 'loginctl terminate-user $USER',
  63. shutdown: 'systemctl poweroff'
  64. };
  65. default:
  66. return {
  67. logout: null,
  68. shutdown: null
  69. };
  70. }
  71. };
  72. const executeSystemCommand = async (command, requiresAdmin = false) => {
  73. try {
  74. if (!command) {
  75. throw new Error('当前平台不支持该操作');
  76. }
  77. // Windows平台的权限检查
  78. if (process.platform === 'win32' && requiresAdmin) {
  79. // 检查是否以管理员身份运行
  80. try {
  81. await execAsync('net session', { timeout: 5000 });
  82. } catch (adminCheckError) {
  83. writeLog('warn', '操作可能需要管理员权限');
  84. return {
  85. success: false,
  86. error: '该操作需要管理员权限,请以管理员身份运行程序后重试',
  87. requiresAdmin: true
  88. };
  89. }
  90. }
  91. const { stdout, stderr } = await execAsync(command, { timeout: 10000 });
  92. writeLog('info', `系统命令执行成功: ${command}`);
  93. if (stderr && stderr.trim()) {
  94. writeLog('warn', `系统命令有警告信息: ${stderr}`);
  95. }
  96. return { success: true, stdout, stderr };
  97. } catch (error) {
  98. let errorMessage = error.message;
  99. // 特定错误类型的处理
  100. if (error.code === 'EACCES') {
  101. errorMessage = '权限不足,请以管理员身份运行程序';
  102. } else if (error.code === 'ENOENT') {
  103. errorMessage = '系统命令不存在或路径错误';
  104. } else if (error.code === 'ETIMEDOUT') {
  105. errorMessage = '操作超时,请重试';
  106. }
  107. writeLog('error', `系统命令执行失败: ${command}, 错误: ${errorMessage}`);
  108. return { success: false, error: errorMessage };
  109. }
  110. };
  111. // -------------- IPC --------------
  112. ipcMain.handle('write-log', async (_, level, msg) => {
  113. writeLog(level, msg);
  114. });
  115. // 退出应用
  116. ipcMain.handle('exit-close', async () => {
  117. writeLog('info', '用户选择关闭应用程序');
  118. app.quit();
  119. return { success: true };
  120. });
  121. // 注销用户
  122. ipcMain.handle('exit-logout', async () => {
  123. writeLog('info', '用户选择注销系统');
  124. const commands = getSystemCommands();
  125. // 注销通常需要管理员权限(Windows平台)
  126. const requiresAdmin = process.platform === 'win32';
  127. return await executeSystemCommand(commands.logout, requiresAdmin);
  128. });
  129. // 关机
  130. ipcMain.handle('exit-shutdown', async () => {
  131. writeLog('info', '用户选择关机');
  132. const commands = getSystemCommands();
  133. // 关机通常需要管理员权限
  134. const requiresAdmin = true;
  135. return await executeSystemCommand(commands.shutdown, requiresAdmin);
  136. });