diff --git a/README.md b/README.md index 4128970..bca3842 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # PHPer 开发环境管理器

- PHPer Logo + PHPer Logo

@@ -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 private basePath: string @@ -35,7 +48,7 @@ export class ConfigStore { constructor() { this.store = new Store({ defaults: { - basePath: join(app.getPath('userData'), 'PHPer'), + basePath: getDefaultBasePath(), phpVersions: [], mysqlVersions: [], nginxVersions: [], diff --git a/icon.ico b/icon.ico deleted file mode 100644 index 6069d26..0000000 Binary files a/icon.ico and /dev/null differ diff --git a/index.html b/index.html index f3542c2..50d9edb 100644 --- a/index.html +++ b/index.html @@ -2,7 +2,7 @@ - + PHPer 开发环境管理器 diff --git a/public/favicon.svg b/public/favicon.svg deleted file mode 100644 index 02d324c..0000000 --- a/public/favicon.svg +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - P - - - diff --git a/public/icon.ico b/public/icon.ico deleted file mode 100644 index 6069d26..0000000 Binary files a/public/icon.ico and /dev/null differ diff --git a/public/icon.png b/public/icon.png new file mode 100644 index 0000000..b7e0e88 Binary files /dev/null and b/public/icon.png differ diff --git a/public/icon.svg b/public/icon.svg new file mode 100644 index 0000000..e63eda5 --- /dev/null +++ b/public/icon.svg @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PHP + diff --git a/src/App.vue b/src/App.vue index 4f879f5..de1142f 100644 --- a/src/App.vue +++ b/src/App.vue @@ -4,7 +4,7 @@

diff --git a/src/views/Settings.vue b/src/views/Settings.vue index 7b87084..1c5bae0 100644 --- a/src/views/Settings.vue +++ b/src/views/Settings.vue @@ -120,7 +120,7 @@
- logo + logo

PHPer 开发环境管理器