diff --git a/README.md b/README.md index 4128970..bca3842 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # PHPer 开发环境管理器
-
+
@@ -168,7 +168,7 @@ phper/
│ └── Settings.vue # 设置
│
├── public/ # 静态资源
-│ └── icon.ico # 应用图标
+│ └── icon.svg # 应用图标
│
├── index.html # HTML 模板
├── package.json # 项目配置
diff --git a/electron/main.ts b/electron/main.ts
index 2565f13..3204302 100644
--- a/electron/main.ts
+++ b/electron/main.ts
@@ -1,346 +1,523 @@
-import { app, BrowserWindow, ipcMain, shell, Tray, Menu, nativeImage } from 'electron'
-import { join } from 'path'
-import { PhpManager } from './services/PhpManager'
-import { MysqlManager } from './services/MysqlManager'
-import { NginxManager } from './services/NginxManager'
-import { RedisManager } from './services/RedisManager'
-import { NodeManager } from './services/NodeManager'
-import { ServiceManager } from './services/ServiceManager'
-import { HostsManager } from './services/HostsManager'
-import { ConfigStore } from './services/ConfigStore'
+import {
+ app,
+ BrowserWindow,
+ ipcMain,
+ shell,
+ Tray,
+ Menu,
+ nativeImage,
+} from "electron";
+import { join } from "path";
+import { PhpManager } from "./services/PhpManager";
+import { MysqlManager } from "./services/MysqlManager";
+import { NginxManager } from "./services/NginxManager";
+import { RedisManager } from "./services/RedisManager";
+import { NodeManager } from "./services/NodeManager";
+import { ServiceManager } from "./services/ServiceManager";
+import { HostsManager } from "./services/HostsManager";
+import { ConfigStore } from "./services/ConfigStore";
-let mainWindow: BrowserWindow | null = null
-let tray: Tray | null = null
-let isQuitting = false
+// 获取托盘图标路径 (使用 PNG)
+function getTrayIconPath(): string {
+ const { existsSync } = require("fs");
+ const paths = [
+ join(__dirname, "../public/icon.png"),
+ join(__dirname, "../dist/icon.png"),
+ ];
+ for (const p of paths) {
+ if (existsSync(p)) return p;
+ }
+ return join(__dirname, "../public/icon.svg");
+}
+
+// 获取窗口图标路径 (使用 SVG)
+function getWindowIconPath(): string {
+ const { existsSync } = require("fs");
+ const paths = [
+ join(__dirname, "../public/icon.svg"),
+ join(__dirname, "../dist/icon.svg"),
+ ];
+ for (const p of paths) {
+ if (existsSync(p)) return p;
+ }
+ return join(__dirname, "../public/icon.png");
+}
+
+// 创建托盘图标
+function createTrayIcon(): Electron.NativeImage {
+ const iconPath = getTrayIconPath();
+ console.log("Tray icon path:", iconPath);
+ try {
+ const icon = nativeImage.createFromPath(iconPath);
+ if (!icon.isEmpty()) {
+ // 托盘图标需要较小尺寸
+ return icon.resize({ width: 16, height: 16 });
+ }
+ } catch (e) {
+ console.error("Failed to load tray icon:", e);
+ }
+ return nativeImage.createEmpty();
+}
+
+// 创建窗口图标
+function createWindowIcon(): Electron.NativeImage {
+ const iconPath = getWindowIconPath();
+ console.log("Window icon path:", iconPath);
+ try {
+ const icon = nativeImage.createFromPath(iconPath);
+ if (!icon.isEmpty()) {
+ return icon;
+ }
+ } catch (e) {
+ console.error("Failed to load window icon:", e);
+ }
+ return nativeImage.createEmpty();
+}
+
+let mainWindow: BrowserWindow | null = null;
+let tray: Tray | null = null;
+let isQuitting = false;
// 发送下载进度到渲染进程
-export function sendDownloadProgress(type: string, progress: number, downloaded: number, total: number) {
+export function sendDownloadProgress(
+ type: string,
+ progress: number,
+ downloaded: number,
+ total: number
+) {
if (mainWindow && !mainWindow.isDestroyed()) {
- mainWindow.webContents.send('download-progress', { type, progress, downloaded, total })
+ mainWindow.webContents.send("download-progress", {
+ type,
+ progress,
+ downloaded,
+ total,
+ });
}
}
// 初始化各服务管理器
-const configStore = new ConfigStore()
-const phpManager = new PhpManager(configStore)
-const mysqlManager = new MysqlManager(configStore)
-const nginxManager = new NginxManager(configStore)
-const redisManager = new RedisManager(configStore)
-const nodeManager = new NodeManager(configStore)
-const serviceManager = new ServiceManager(configStore)
-const hostsManager = new HostsManager()
+const configStore = new ConfigStore();
+const phpManager = new PhpManager(configStore);
+const mysqlManager = new MysqlManager(configStore);
+const nginxManager = new NginxManager(configStore);
+const redisManager = new RedisManager(configStore);
+const nodeManager = new NodeManager(configStore);
+const serviceManager = new ServiceManager(configStore);
+const hostsManager = new HostsManager();
function createWindow() {
+ const appIcon = createWindowIcon();
+
mainWindow = new BrowserWindow({
width: 1400,
height: 900,
minWidth: 1200,
minHeight: 700,
webPreferences: {
- preload: join(__dirname, 'preload.js'),
+ preload: join(__dirname, "preload.js"),
contextIsolation: true,
- nodeIntegration: false
+ nodeIntegration: false,
},
- titleBarStyle: 'hidden',
+ titleBarStyle: "hidden",
titleBarOverlay: {
- color: '#1a1a2e',
- symbolColor: '#ffffff',
- height: 40
+ color: "#1a1a2e",
+ symbolColor: "#ffffff",
+ height: 40,
},
frame: false,
- icon: join(__dirname, '../public/icon.ico'),
- show: false // 先不显示,等 ready-to-show
- })
+ icon: appIcon,
+ show: false, // 先不显示,等 ready-to-show
+ });
// 开发环境加载 Vite 开发服务器
- const VITE_DEV_SERVER_URL = process.env.VITE_DEV_SERVER_URL
+ const VITE_DEV_SERVER_URL = process.env.VITE_DEV_SERVER_URL;
if (VITE_DEV_SERVER_URL) {
- mainWindow.loadURL(VITE_DEV_SERVER_URL)
- mainWindow.webContents.openDevTools()
+ mainWindow.loadURL(VITE_DEV_SERVER_URL);
+ mainWindow.webContents.openDevTools();
} else {
- mainWindow.loadFile(join(__dirname, '../dist/index.html'))
+ mainWindow.loadFile(join(__dirname, "../dist/index.html"));
}
// 窗口准备好后显示
- mainWindow.once('ready-to-show', () => {
+ mainWindow.once("ready-to-show", () => {
// 检查是否开机自启且静默启动
- const startMinimized = configStore.get('startMinimized')
+ const startMinimized = configStore.get("startMinimized");
if (!startMinimized) {
- mainWindow?.show()
+ mainWindow?.show();
}
- })
+ });
// 关闭按钮改为最小化到托盘
- mainWindow.on('close', (event) => {
+ mainWindow.on("close", (event) => {
if (!isQuitting) {
- event.preventDefault()
- mainWindow?.hide()
+ event.preventDefault();
+ mainWindow?.hide();
}
- })
+ });
- mainWindow.on('closed', () => {
- mainWindow = null
- })
+ mainWindow.on("closed", () => {
+ mainWindow = null;
+ });
}
// 创建系统托盘
function createTray() {
// 创建托盘图标
- const iconPath = join(__dirname, '../public/favicon.svg')
- let trayIcon
-
- try {
- trayIcon = nativeImage.createFromPath(iconPath)
- if (trayIcon.isEmpty()) {
- // 如果 SVG 无法加载,创建一个简单的图标
- trayIcon = nativeImage.createEmpty()
- }
- } catch (e) {
- trayIcon = nativeImage.createEmpty()
- }
+ const trayIcon = createTrayIcon();
- tray = new Tray(trayIcon)
- tray.setToolTip('PHPer 开发环境管理器')
+ tray = new Tray(trayIcon);
+ tray.setToolTip("PHPer 开发环境管理器");
// 创建托盘菜单
const contextMenu = Menu.buildFromTemplate([
{
- label: '显示主窗口',
+ label: "显示主窗口",
click: () => {
if (mainWindow) {
- mainWindow.show()
- mainWindow.focus()
+ mainWindow.show();
+ mainWindow.focus();
} else {
- createWindow()
+ createWindow();
}
- }
+ },
},
- { type: 'separator' },
+ { type: "separator" },
{
- label: '启动全部服务',
+ label: "启动全部服务",
click: async () => {
- const result = await serviceManager.startAll()
+ const result = await serviceManager.startAll();
if (mainWindow && !mainWindow.isDestroyed()) {
- mainWindow.webContents.send('service-status-changed')
+ mainWindow.webContents.send("service-status-changed");
}
- }
+ },
},
{
- label: '停止全部服务',
+ label: "停止全部服务",
click: async () => {
- const result = await serviceManager.stopAll()
+ const result = await serviceManager.stopAll();
if (mainWindow && !mainWindow.isDestroyed()) {
- mainWindow.webContents.send('service-status-changed')
+ mainWindow.webContents.send("service-status-changed");
}
- }
+ },
},
- { type: 'separator' },
+ { type: "separator" },
{
- label: '退出',
+ label: "退出",
click: () => {
- isQuitting = true
- app.quit()
- }
- }
- ])
+ isQuitting = true;
+ app.quit();
+ },
+ },
+ ]);
- tray.setContextMenu(contextMenu)
+ tray.setContextMenu(contextMenu);
// 双击托盘图标显示窗口
- tray.on('double-click', () => {
+ tray.on("double-click", () => {
if (mainWindow) {
- mainWindow.show()
- mainWindow.focus()
+ mainWindow.show();
+ mainWindow.focus();
} else {
- createWindow()
+ createWindow();
}
- })
+ });
}
app.whenReady().then(async () => {
- createTray()
- createWindow()
+ createTray();
+ createWindow();
// 检查是否启用开机自启且自动启动服务
- const autoStartServices = configStore.get('autoStartServicesOnBoot')
+ const autoStartServices = configStore.get("autoStartServicesOnBoot");
if (autoStartServices) {
- await serviceManager.startAll()
+ await serviceManager.startAll();
}
- app.on('activate', () => {
+ app.on("activate", () => {
if (BrowserWindow.getAllWindows().length === 0) {
- createWindow()
+ createWindow();
}
- })
-})
+ });
+});
// 不要在所有窗口关闭时退出,保持托盘运行
-app.on('window-all-closed', () => {
+app.on("window-all-closed", () => {
// 什么都不做,保持后台运行
-})
+});
// 真正退出前清理
-app.on('before-quit', () => {
- isQuitting = true
-})
+app.on("before-quit", () => {
+ isQuitting = true;
+});
// ==================== IPC 处理程序 ====================
// 窗口控制
-ipcMain.handle('window:minimize', () => mainWindow?.minimize())
-ipcMain.handle('window:maximize', () => {
+ipcMain.handle("window:minimize", () => mainWindow?.minimize());
+ipcMain.handle("window:maximize", () => {
if (mainWindow?.isMaximized()) {
- mainWindow.unmaximize()
+ mainWindow.unmaximize();
} else {
- mainWindow?.maximize()
+ mainWindow?.maximize();
}
-})
-ipcMain.handle('window:close', () => mainWindow?.close())
+});
+ipcMain.handle("window:close", () => mainWindow?.close());
// 打开外部链接
-ipcMain.handle('shell:openExternal', (_, url: string) => shell.openExternal(url))
-ipcMain.handle('shell:openPath', (_, path: string) => shell.openPath(path))
+ipcMain.handle("shell:openExternal", (_, url: string) =>
+ shell.openExternal(url)
+);
+ipcMain.handle("shell:openPath", (_, path: string) => shell.openPath(path));
// 选择文件夹对话框
-ipcMain.handle('dialog:selectDirectory', async () => {
- const { dialog } = await import('electron')
+ipcMain.handle("dialog:selectDirectory", async () => {
+ const { dialog } = await import("electron");
const result = await dialog.showOpenDialog(mainWindow!, {
- properties: ['openDirectory'],
- title: '选择目录'
- })
- return result.canceled ? null : result.filePaths[0]
-})
+ properties: ["openDirectory"],
+ title: "选择目录",
+ });
+ return result.canceled ? null : result.filePaths[0];
+});
// ==================== PHP 管理 ====================
-ipcMain.handle('php:getVersions', () => phpManager.getInstalledVersions())
-ipcMain.handle('php:getAvailableVersions', () => phpManager.getAvailableVersions())
-ipcMain.handle('php:install', (_, version: string) => phpManager.install(version))
-ipcMain.handle('php:uninstall', (_, version: string) => phpManager.uninstall(version))
-ipcMain.handle('php:setActive', (_, version: string) => phpManager.setActive(version))
-ipcMain.handle('php:getExtensions', (_, version: string) => phpManager.getExtensions(version))
-ipcMain.handle('php:openExtensionDir', (_, version: string) => phpManager.openExtensionDir(version))
-ipcMain.handle('php:getAvailableExtensions', (_, version: string, searchKeyword?: string) => phpManager.getAvailableExtensions(version, searchKeyword))
-ipcMain.handle('php:enableExtension', (_, version: string, ext: string) => phpManager.enableExtension(version, ext))
-ipcMain.handle('php:disableExtension', (_, version: string, ext: string) => phpManager.disableExtension(version, ext))
-ipcMain.handle('php:installExtension', (_, version: string, ext: string, downloadUrl?: string, packageName?: string) => phpManager.installExtension(version, ext, downloadUrl, packageName))
-ipcMain.handle('php:getConfig', (_, version: string) => phpManager.getConfig(version))
-ipcMain.handle('php:saveConfig', (_, version: string, config: string) => phpManager.saveConfig(version, config))
+ipcMain.handle("php:getVersions", () => phpManager.getInstalledVersions());
+ipcMain.handle("php:getAvailableVersions", () =>
+ phpManager.getAvailableVersions()
+);
+ipcMain.handle("php:install", (_, version: string) =>
+ phpManager.install(version)
+);
+ipcMain.handle("php:uninstall", (_, version: string) =>
+ phpManager.uninstall(version)
+);
+ipcMain.handle("php:setActive", (_, version: string) =>
+ phpManager.setActive(version)
+);
+ipcMain.handle("php:getExtensions", (_, version: string) =>
+ phpManager.getExtensions(version)
+);
+ipcMain.handle("php:openExtensionDir", (_, version: string) =>
+ phpManager.openExtensionDir(version)
+);
+ipcMain.handle(
+ "php:getAvailableExtensions",
+ (_, version: string, searchKeyword?: string) =>
+ phpManager.getAvailableExtensions(version, searchKeyword)
+);
+ipcMain.handle("php:enableExtension", (_, version: string, ext: string) =>
+ phpManager.enableExtension(version, ext)
+);
+ipcMain.handle("php:disableExtension", (_, version: string, ext: string) =>
+ phpManager.disableExtension(version, ext)
+);
+ipcMain.handle(
+ "php:installExtension",
+ (
+ _,
+ version: string,
+ ext: string,
+ downloadUrl?: string,
+ packageName?: string
+ ) => phpManager.installExtension(version, ext, downloadUrl, packageName)
+);
+ipcMain.handle("php:getConfig", (_, version: string) =>
+ phpManager.getConfig(version)
+);
+ipcMain.handle("php:saveConfig", (_, version: string, config: string) =>
+ phpManager.saveConfig(version, config)
+);
// ==================== MySQL 管理 ====================
-ipcMain.handle('mysql:getVersions', () => mysqlManager.getInstalledVersions())
-ipcMain.handle('mysql:getAvailableVersions', () => mysqlManager.getAvailableVersions())
-ipcMain.handle('mysql:install', (_, version: string) => mysqlManager.install(version))
-ipcMain.handle('mysql:uninstall', (_, version: string) => mysqlManager.uninstall(version))
-ipcMain.handle('mysql:start', (_, version: string) => mysqlManager.start(version))
-ipcMain.handle('mysql:stop', (_, version: string) => mysqlManager.stop(version))
-ipcMain.handle('mysql:restart', (_, version: string) => mysqlManager.restart(version))
-ipcMain.handle('mysql:getStatus', (_, version: string) => mysqlManager.getStatus(version))
-ipcMain.handle('mysql:changePassword', (_, version: string, newPassword: string, currentPassword?: string) => mysqlManager.changeRootPassword(version, newPassword, currentPassword))
-ipcMain.handle('mysql:getConfig', (_, version: string) => mysqlManager.getConfig(version))
-ipcMain.handle('mysql:saveConfig', (_, version: string, config: string) => mysqlManager.saveConfig(version, config))
-ipcMain.handle('mysql:reinitialize', (_, version: string) => mysqlManager.reinitialize(version))
+ipcMain.handle("mysql:getVersions", () => mysqlManager.getInstalledVersions());
+ipcMain.handle("mysql:getAvailableVersions", () =>
+ mysqlManager.getAvailableVersions()
+);
+ipcMain.handle("mysql:install", (_, version: string) =>
+ mysqlManager.install(version)
+);
+ipcMain.handle("mysql:uninstall", (_, version: string) =>
+ mysqlManager.uninstall(version)
+);
+ipcMain.handle("mysql:start", (_, version: string) =>
+ mysqlManager.start(version)
+);
+ipcMain.handle("mysql:stop", (_, version: string) =>
+ mysqlManager.stop(version)
+);
+ipcMain.handle("mysql:restart", (_, version: string) =>
+ mysqlManager.restart(version)
+);
+ipcMain.handle("mysql:getStatus", (_, version: string) =>
+ mysqlManager.getStatus(version)
+);
+ipcMain.handle(
+ "mysql:changePassword",
+ (_, version: string, newPassword: string, currentPassword?: string) =>
+ mysqlManager.changeRootPassword(version, newPassword, currentPassword)
+);
+ipcMain.handle("mysql:getConfig", (_, version: string) =>
+ mysqlManager.getConfig(version)
+);
+ipcMain.handle("mysql:saveConfig", (_, version: string, config: string) =>
+ mysqlManager.saveConfig(version, config)
+);
+ipcMain.handle("mysql:reinitialize", (_, version: string) =>
+ mysqlManager.reinitialize(version)
+);
// ==================== Nginx 管理 ====================
-ipcMain.handle('nginx:getVersions', () => nginxManager.getInstalledVersions())
-ipcMain.handle('nginx:getAvailableVersions', () => nginxManager.getAvailableVersions())
-ipcMain.handle('nginx:install', (_, version: string) => nginxManager.install(version))
-ipcMain.handle('nginx:uninstall', (_, version: string) => nginxManager.uninstall(version))
-ipcMain.handle('nginx:start', () => nginxManager.start())
-ipcMain.handle('nginx:stop', () => nginxManager.stop())
-ipcMain.handle('nginx:restart', () => nginxManager.restart())
-ipcMain.handle('nginx:reload', () => nginxManager.reload())
-ipcMain.handle('nginx:getStatus', () => nginxManager.getStatus())
-ipcMain.handle('nginx:getConfig', () => nginxManager.getConfig())
-ipcMain.handle('nginx:saveConfig', (_, config: string) => nginxManager.saveConfig(config))
-ipcMain.handle('nginx:getSites', () => nginxManager.getSites())
-ipcMain.handle('nginx:addSite', (_, site: any) => nginxManager.addSite(site))
-ipcMain.handle('nginx:removeSite', (_, name: string) => nginxManager.removeSite(name))
-ipcMain.handle('nginx:updateSite', (_, originalName: string, site: any) => nginxManager.updateSite(originalName, site))
-ipcMain.handle('nginx:enableSite', (_, name: string) => nginxManager.enableSite(name))
-ipcMain.handle('nginx:disableSite', (_, name: string) => nginxManager.disableSite(name))
-ipcMain.handle('nginx:generateLaravelConfig', (_, site: any) => nginxManager.generateLaravelConfig(site))
-ipcMain.handle('nginx:requestSSL', (_, domain: string, email: string) => nginxManager.requestSSLCertificate(domain, email))
+ipcMain.handle("nginx:getVersions", () => nginxManager.getInstalledVersions());
+ipcMain.handle("nginx:getAvailableVersions", () =>
+ nginxManager.getAvailableVersions()
+);
+ipcMain.handle("nginx:install", (_, version: string) =>
+ nginxManager.install(version)
+);
+ipcMain.handle("nginx:uninstall", (_, version: string) =>
+ nginxManager.uninstall(version)
+);
+ipcMain.handle("nginx:start", () => nginxManager.start());
+ipcMain.handle("nginx:stop", () => nginxManager.stop());
+ipcMain.handle("nginx:restart", () => nginxManager.restart());
+ipcMain.handle("nginx:reload", () => nginxManager.reload());
+ipcMain.handle("nginx:getStatus", () => nginxManager.getStatus());
+ipcMain.handle("nginx:getConfig", () => nginxManager.getConfig());
+ipcMain.handle("nginx:saveConfig", (_, config: string) =>
+ nginxManager.saveConfig(config)
+);
+ipcMain.handle("nginx:getSites", () => nginxManager.getSites());
+ipcMain.handle("nginx:addSite", (_, site: any) => nginxManager.addSite(site));
+ipcMain.handle("nginx:removeSite", (_, name: string) =>
+ nginxManager.removeSite(name)
+);
+ipcMain.handle("nginx:updateSite", (_, originalName: string, site: any) =>
+ nginxManager.updateSite(originalName, site)
+);
+ipcMain.handle("nginx:enableSite", (_, name: string) =>
+ nginxManager.enableSite(name)
+);
+ipcMain.handle("nginx:disableSite", (_, name: string) =>
+ nginxManager.disableSite(name)
+);
+ipcMain.handle("nginx:generateLaravelConfig", (_, site: any) =>
+ nginxManager.generateLaravelConfig(site)
+);
+ipcMain.handle("nginx:requestSSL", (_, domain: string, email: string) =>
+ nginxManager.requestSSLCertificate(domain, email)
+);
// ==================== Redis 管理 ====================
-ipcMain.handle('redis:getVersions', () => redisManager.getInstalledVersions())
-ipcMain.handle('redis:getAvailableVersions', () => redisManager.getAvailableVersions())
-ipcMain.handle('redis:install', (_, version: string) => redisManager.install(version))
-ipcMain.handle('redis:uninstall', (_, version: string) => redisManager.uninstall(version))
-ipcMain.handle('redis:start', () => redisManager.start())
-ipcMain.handle('redis:stop', () => redisManager.stop())
-ipcMain.handle('redis:restart', () => redisManager.restart())
-ipcMain.handle('redis:getStatus', () => redisManager.getStatus())
-ipcMain.handle('redis:getConfig', () => redisManager.getConfig())
-ipcMain.handle('redis:saveConfig', (_, config: string) => redisManager.saveConfig(config))
+ipcMain.handle("redis:getVersions", () => redisManager.getInstalledVersions());
+ipcMain.handle("redis:getAvailableVersions", () =>
+ redisManager.getAvailableVersions()
+);
+ipcMain.handle("redis:install", (_, version: string) =>
+ redisManager.install(version)
+);
+ipcMain.handle("redis:uninstall", (_, version: string) =>
+ redisManager.uninstall(version)
+);
+ipcMain.handle("redis:start", () => redisManager.start());
+ipcMain.handle("redis:stop", () => redisManager.stop());
+ipcMain.handle("redis:restart", () => redisManager.restart());
+ipcMain.handle("redis:getStatus", () => redisManager.getStatus());
+ipcMain.handle("redis:getConfig", () => redisManager.getConfig());
+ipcMain.handle("redis:saveConfig", (_, config: string) =>
+ redisManager.saveConfig(config)
+);
// ==================== Node.js 管理 ====================
-ipcMain.handle('node:getVersions', () => nodeManager.getInstalledVersions())
-ipcMain.handle('node:getAvailableVersions', () => nodeManager.getAvailableVersions())
-ipcMain.handle('node:install', (_, version: string, downloadUrl: string) => nodeManager.install(version, downloadUrl))
-ipcMain.handle('node:uninstall', (_, version: string) => nodeManager.uninstall(version))
-ipcMain.handle('node:setActive', (_, version: string) => nodeManager.setActive(version))
-ipcMain.handle('node:getInfo', (_, version: string) => nodeManager.getNodeInfo(version))
+ipcMain.handle("node:getVersions", () => nodeManager.getInstalledVersions());
+ipcMain.handle("node:getAvailableVersions", () =>
+ nodeManager.getAvailableVersions()
+);
+ipcMain.handle("node:install", (_, version: string, downloadUrl: string) =>
+ nodeManager.install(version, downloadUrl)
+);
+ipcMain.handle("node:uninstall", (_, version: string) =>
+ nodeManager.uninstall(version)
+);
+ipcMain.handle("node:setActive", (_, version: string) =>
+ nodeManager.setActive(version)
+);
+ipcMain.handle("node:getInfo", (_, version: string) =>
+ nodeManager.getNodeInfo(version)
+);
// ==================== 服务管理 ====================
-ipcMain.handle('service:getAll', () => serviceManager.getAllServices())
-ipcMain.handle('service:setAutoStart', (_, service: string, enabled: boolean) => serviceManager.setAutoStart(service, enabled))
-ipcMain.handle('service:getAutoStart', (_, service: string) => serviceManager.getAutoStart(service))
-ipcMain.handle('service:startAll', () => serviceManager.startAll())
-ipcMain.handle('service:stopAll', () => serviceManager.stopAll())
+ipcMain.handle("service:getAll", () => serviceManager.getAllServices());
+ipcMain.handle("service:setAutoStart", (_, service: string, enabled: boolean) =>
+ serviceManager.setAutoStart(service, enabled)
+);
+ipcMain.handle("service:getAutoStart", (_, service: string) =>
+ serviceManager.getAutoStart(service)
+);
+ipcMain.handle("service:startAll", () => serviceManager.startAll());
+ipcMain.handle("service:stopAll", () => serviceManager.stopAll());
// ==================== Hosts 管理 ====================
-ipcMain.handle('hosts:get', () => hostsManager.getHosts())
-ipcMain.handle('hosts:add', (_, domain: string, ip: string) => hostsManager.addHost(domain, ip))
-ipcMain.handle('hosts:remove', (_, domain: string) => hostsManager.removeHost(domain))
+ipcMain.handle("hosts:get", () => hostsManager.getHosts());
+ipcMain.handle("hosts:add", (_, domain: string, ip: string) =>
+ hostsManager.addHost(domain, ip)
+);
+ipcMain.handle("hosts:remove", (_, domain: string) =>
+ hostsManager.removeHost(domain)
+);
// ==================== 配置管理 ====================
-ipcMain.handle('config:get', (_, key: string) => configStore.get(key))
-ipcMain.handle('config:set', (_, key: string, value: any) => configStore.set(key, value))
-ipcMain.handle('config:getBasePath', () => configStore.getBasePath())
-ipcMain.handle('config:setBasePath', (_, path: string) => configStore.setBasePath(path))
+ipcMain.handle("config:get", (_, key: string) => configStore.get(key));
+ipcMain.handle("config:set", (_, key: string, value: any) =>
+ configStore.set(key, value)
+);
+ipcMain.handle("config:getBasePath", () => configStore.getBasePath());
+ipcMain.handle("config:setBasePath", (_, path: string) =>
+ configStore.setBasePath(path)
+);
// ==================== 应用设置 ====================
// 设置开机自启
-ipcMain.handle('app:setAutoLaunch', async (_, enabled: boolean) => {
+ipcMain.handle("app:setAutoLaunch", async (_, enabled: boolean) => {
app.setLoginItemSettings({
openAtLogin: enabled,
openAsHidden: true, // 静默启动
- args: ['--hidden']
- })
- configStore.set('autoLaunch', enabled)
- return { success: true, message: enabled ? '已启用开机自启' : '已禁用开机自启' }
-})
+ args: ["--hidden"],
+ });
+ configStore.set("autoLaunch", enabled);
+ return {
+ success: true,
+ message: enabled ? "已启用开机自启" : "已禁用开机自启",
+ };
+});
// 获取开机自启状态
-ipcMain.handle('app:getAutoLaunch', () => {
- return app.getLoginItemSettings().openAtLogin
-})
+ipcMain.handle("app:getAutoLaunch", () => {
+ return app.getLoginItemSettings().openAtLogin;
+});
// 设置启动时最小化到托盘
-ipcMain.handle('app:setStartMinimized', (_, enabled: boolean) => {
- configStore.set('startMinimized', enabled)
- return { success: true }
-})
+ipcMain.handle("app:setStartMinimized", (_, enabled: boolean) => {
+ configStore.set("startMinimized", enabled);
+ return { success: true };
+});
// 获取启动时最小化状态
-ipcMain.handle('app:getStartMinimized', () => {
- return configStore.get('startMinimized') || false
-})
+ipcMain.handle("app:getStartMinimized", () => {
+ return configStore.get("startMinimized") || false;
+});
// 设置开机自启时自动启动服务
-ipcMain.handle('app:setAutoStartServices', (_, enabled: boolean) => {
- configStore.set('autoStartServicesOnBoot', enabled)
- return { success: true }
-})
+ipcMain.handle("app:setAutoStartServices", (_, enabled: boolean) => {
+ configStore.set("autoStartServicesOnBoot", enabled);
+ return { success: true };
+});
// 获取自动启动服务状态
-ipcMain.handle('app:getAutoStartServices', () => {
- return configStore.get('autoStartServicesOnBoot') || false
-})
+ipcMain.handle("app:getAutoStartServices", () => {
+ return configStore.get("autoStartServicesOnBoot") || false;
+});
// 真正退出应用
-ipcMain.handle('app:quit', () => {
- isQuitting = true
- app.quit()
-})
-
+ipcMain.handle("app:quit", () => {
+ isQuitting = true;
+ app.quit();
+});
diff --git a/electron/services/ConfigStore.ts b/electron/services/ConfigStore.ts
index f5a627c..a83fe90 100644
--- a/electron/services/ConfigStore.ts
+++ b/electron/services/ConfigStore.ts
@@ -1,5 +1,5 @@
import Store from 'electron-store'
-import { join } from 'path'
+import { join, dirname } from 'path'
import { existsSync, mkdirSync } from 'fs'
import { app } from 'electron'
@@ -28,6 +28,19 @@ export interface SiteConfig {
enabled: boolean
}
+// 获取应用安装目录下的 data 路径
+function getDefaultBasePath(): string {
+ if (app.isPackaged) {
+ // 生产环境:使用可执行文件所在目录下的 data 文件夹
+ const exePath = app.getPath('exe')
+ const appDir = dirname(exePath)
+ return join(appDir, 'data')
+ } else {
+ // 开发环境:使用项目根目录下的 data 文件夹
+ return join(process.cwd(), 'data')
+ }
+}
+
export class ConfigStore {
private store: Store