From 37a35043d76223de36ba2002cf15c5df6aada2af Mon Sep 17 00:00:00 2001 From: xianyunleo Date: Sat, 21 Sep 2024 19:22:59 +0800 Subject: [PATCH] =?UTF-8?q?=E9=87=8D=E6=9E=84=E4=BB=A3=E7=A0=81=EF=BC=8C?= =?UTF-8?q?=E7=A7=BB=E9=99=A4electron/remote?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- electron.vite.config.js | 13 +- package.json | 1 - src/main/App.js | 12 - src/main/MainWindow.js | 74 +++--- src/main/TrayManage.js | 108 ++++---- src/main/common/call.js | 2 +- src/main/core/Env/Env.js | 2 +- src/main/core/Env/EnvMacOS.js | 5 +- src/main/core/Nginx.js | 8 +- src/main/core/php/extension/Installer.js | 202 +++++++-------- src/main/core/software/LocalInstall.js | 4 +- src/main/core/website/NginxWebsite.js | 2 +- src/main/index.js | 4 - src/main/ipcListen.js | 31 ++- src/main/utils/FileDialog.js | 125 +++++----- src/main/utils/GetAppPath.js | 34 +-- src/main/utils/Native.js | 4 +- src/main/utils/OS.js | 130 +++++----- src/main/utils/Path.js | 102 ++++---- src/main/utils/SystemTheme.js | 16 +- src/main/utils/TcpProcess.js | 45 ++-- src/main/utils/electron.js | 16 -- src/main/utils/utils.js | 43 ++-- src/preload/index.js | 60 ++--- src/renderer/App.vue | 12 +- .../components/Input/InputOpenDirDialog.vue | 80 +++--- .../components/Input/InputOpenFileDialog.vue | 7 +- src/renderer/components/Settings/Other.vue | 11 +- src/renderer/components/SideBar.vue | 166 ++++++------ .../components/Theme/ConfigProvider.vue | 6 +- src/renderer/components/TitleBar.vue | 235 +++++++++-------- src/renderer/components/UserPwdModal.vue | 8 +- src/renderer/views/About.vue | 7 +- src/renderer/views/Software.vue | 5 +- src/shared/utils/GetPath.js | 236 +++++++++--------- src/shared/utils/file.js | 8 + src/shared/utils/window.js | 13 - 37 files changed, 900 insertions(+), 937 deletions(-) delete mode 100644 src/main/utils/electron.js create mode 100644 src/shared/utils/file.js delete mode 100644 src/shared/utils/window.js diff --git a/electron.vite.config.js b/electron.vite.config.js index f128235c..ab1aa714 100644 --- a/electron.vite.config.js +++ b/electron.vite.config.js @@ -1,12 +1,12 @@ import { resolve } from 'path' -import { defineConfig, externalizeDepsPlugin, splitVendorChunkPlugin } from 'electron-vite' +import { defineConfig, externalizeDepsPlugin } from 'electron-vite' import vue from '@vitejs/plugin-vue' import commonjsExternals from 'vite-plugin-commonjs-externals' import Components from 'unplugin-vue-components/vite' import { AntDesignVueResolver } from 'unplugin-vue-components/resolvers' import { builtinModules } from 'module' -const externals = ['fix-path', 'electron-store', '@electron/remote', 'extract-zip', +const externals = ['fix-path', 'electron-store', 'extract-zip', 'hmc-win32', 'net-win32', ...builtinModules, ...builtinModules.map((m) => `node:${m}`)] export default defineConfig({ @@ -22,9 +22,7 @@ export default defineConfig({ plugins: [externalizeDepsPlugin()] }, renderer: { - optimizeDeps: { - exclude: externals - }, + optimizeDeps: { exclude: externals }, resolve: { alias: { '@': resolve('src') @@ -32,10 +30,7 @@ export default defineConfig({ }, plugins: [ vue(), - splitVendorChunkPlugin(), - commonjsExternals({ - externals - }), + commonjsExternals({ externals }), Components({ resolvers: [ AntDesignVueResolver({ diff --git a/package.json b/package.json index 8dbfb40a..412435c1 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,6 @@ "dependencies": { "@electron-toolkit/preload": "^2.0.0", "@electron-toolkit/utils": "^2.0.0", - "@electron/remote": "^2.0.11", "@tiny-libs/nls": "^1.0.1", "7zip-min-electron": "^1.4.4", "electron-dl-downloader": "^1.0.5", diff --git a/src/main/App.js b/src/main/App.js index 09adbcca..68b6c394 100644 --- a/src/main/App.js +++ b/src/main/App.js @@ -1,4 +1,3 @@ -import { electronRequire } from '@/main/utils/electron' import { isDev, isMacOS, isWindows } from '@/main/utils/utils' import path from 'path' import { MAC_USER_CORE_DIR, InitFiles_DIR_NAME, TEMP_DIR_NAME } from '@/main/utils/constant' @@ -13,13 +12,7 @@ import GetAppPath from '@/main/utils/GetAppPath' import Shell from '@/main/utils/Shell' import { extractZip } from '@/main/utils/extract' -const app = electronRequire('app') - export default class App { - static getVersion() { - return app.getVersion() - } - static async initFileExists() { return await FileUtil.Exists(GetAppPath.getInitFilePath()) } @@ -152,9 +145,4 @@ export default class App { } } } - - static exit() { - app.exit() - } - } diff --git a/src/main/MainWindow.js b/src/main/MainWindow.js index 4f7a7015..bb97d0a8 100644 --- a/src/main/MainWindow.js +++ b/src/main/MainWindow.js @@ -1,31 +1,43 @@ -export default class MainWindow { - - static _instance; - static forceQuit = false; - - /** - * - * @param mainWindow {BrowserWindow} - */ - static init(mainWindow) { - if (this._instance) return - this._instance = mainWindow - mainWindow.on('close', (event) => { - if (!this.forceQuit) { - event.preventDefault(); - if (mainWindow.isFullScreen()) { - mainWindow.once('leave-full-screen', () => mainWindow.hide()) - - mainWindow.setFullScreen(false) - } else { - mainWindow.hide() - } - } - }) - } - - static show() { - this._instance.isMinimized() ? this._instance.restore() : this._instance.show() - } - -} +export default class MainWindow { + + static _instance; + static forceQuit = false; + + static getInstance(){ + return this._instance + } + + /** + * + * @param mainWindow {BrowserWindow} + */ + static init(mainWindow) { + if (this._instance) return + this._instance = mainWindow + mainWindow.on('close', (event) => { + if (!this.forceQuit) { + event.preventDefault(); + if (mainWindow.isFullScreen()) { + mainWindow.once('leave-full-screen', () => mainWindow.hide()) + + mainWindow.setFullScreen(false) + } else { + mainWindow.hide() + } + } + }) + + mainWindow.on('maximize', () => { + mainWindow.webContents.send('mainWindowMaximize') + }) + + mainWindow.on('unmaximize', () => { + mainWindow.webContents.send('mainWindowUnmaximize') + }) + } + + static show() { + this._instance.isMinimized() ? this._instance.restore() : this._instance.show() + } + +} diff --git a/src/main/TrayManage.js b/src/main/TrayManage.js index 579af517..51bc686a 100644 --- a/src/main/TrayManage.js +++ b/src/main/TrayManage.js @@ -1,54 +1,54 @@ -import { app, Tray, Menu, nativeImage } from 'electron' -import { APP_NAME } from '@/shared/utils/constant' -import { isMacOS, isWindows } from '@/main/utils/utils' -import { t } from '@/main/utils/i18n' -import Path from '@/main/utils/Path' -import GetAppPath from '@/main/utils/GetAppPath' -import MainWindow from '@/main/MainWindow' - -export default class TrayManage { - static _instance - - static init() { - if (this._instance) return - let iconPath = this.getIconPath() - let icon = nativeImage.createFromPath(iconPath).resize({ width: 18, height: 18 }) - icon.setTemplateImage(true) - let tray = new Tray(icon) - const contextMenu = this.getContextMenu() - tray.setToolTip(APP_NAME) - tray.setContextMenu(contextMenu) - if (isWindows) { - tray.on('click', () => this.showMainWindow()) - } - this._instance = tray - } - - static getContextMenu() { - return Menu.buildFromTemplate([ - { - label: t('Open'), - click: () => this.showMainWindow() - }, - { - label: t('Exit'), - click: () => app.quit() - } - ]) - } - - static showMainWindow() { - MainWindow.show() - } - - static updateContextMenu() { - this._instance.setContextMenu(this.getContextMenu()) - } - - static getIconPath() { - if (isMacOS) { - return Path.Join(GetAppPath.getStaticDir(), 'img/icons/icon-tray-Mac.png') - } - return Path.Join(GetAppPath.getStaticDir(), 'img/icons/icon-tray.png') - } -} +import { app, Tray, Menu, nativeImage } from 'electron' +import { APP_NAME } from '@/shared/utils/constant' +import { isMacOS, isWindows } from '@/main/utils/utils' +import { t } from '@/main/utils/i18n' +import MainWindow from '@/main/MainWindow' +import trayIcon from '@/../resources/img/icons/icon-tray.png?asset' +import trayMacIcon from '@/../resources/img/icons/icon-tray-Mac.png?asset' + +export default class TrayManage { + static _instance + + static init() { + if (this._instance) return + let iconPath = this.getIconPath() + let icon = nativeImage.createFromPath(iconPath).resize({ width: 18, height: 18 }) + icon.setTemplateImage(true) + let tray = new Tray(icon) + const contextMenu = this.getContextMenu() + tray.setToolTip(APP_NAME) + tray.setContextMenu(contextMenu) + if (isWindows) { + tray.on('click', () => this.showMainWindow()) + } + this._instance = tray + } + + static getContextMenu() { + return Menu.buildFromTemplate([ + { + label: t('Open'), + click: () => this.showMainWindow() + }, + { + label: t('Exit'), + click: () => app.quit() + } + ]) + } + + static showMainWindow() { + MainWindow.show() + } + + static updateContextMenu() { + this._instance.setContextMenu(this.getContextMenu()) + } + + static getIconPath() { + if (isMacOS) { + return trayMacIcon + } + return trayIcon + } +} diff --git a/src/main/common/call.js b/src/main/common/call.js index 496d9a98..a816c1d4 100644 --- a/src/main/common/call.js +++ b/src/main/common/call.js @@ -3,7 +3,7 @@ import { Worker } from 'node:worker_threads' export async function callStatic(className, methodName, ...args) { let result, importReturn - const utilsClassArr = ['ProcessLibrary'] + const utilsClassArr = ['ProcessLibrary', 'FileDialog'] if (utilsClassArr.includes(className)) { importReturn = await import(`@/main/utils/${className}.js`) } else if (className === 'I18n') { diff --git a/src/main/core/Env/Env.js b/src/main/core/Env/Env.js index e6a7bc0a..9e583e35 100644 --- a/src/main/core/Env/Env.js +++ b/src/main/core/Env/Env.js @@ -35,7 +35,7 @@ export default class Env { static async createOtherBinFile(targetPath, targetOtherFileName, otherBinName) { let binDirPath = GetPath.getBinDir(); let path = Path.Join(binDirPath, otherBinName); - let targetOtherFilePath = Path.Join(Path.GetDirectoryName(targetPath), targetOtherFileName); + let targetOtherFilePath = Path.Join(Path.GetDirName(targetPath), targetOtherFileName); await FsUtil.CreateSymbolicLink(path, targetOtherFilePath); } diff --git a/src/main/core/Env/EnvMacOS.js b/src/main/core/Env/EnvMacOS.js index 1273ad0b..63c3c5c0 100644 --- a/src/main/core/Env/EnvMacOS.js +++ b/src/main/core/Env/EnvMacOS.js @@ -1,4 +1,3 @@ -import {electronRequire} from '@/main/utils/electron'; import FileUtil from "@/main/utils/FileUtil"; import Path from "@/main/utils/Path"; import OS from "@/main/utils/OS"; @@ -7,13 +6,11 @@ import {APP_NAME} from "@/shared/utils/constant"; import GetPath from "@/shared/utils/GetPath"; import FsUtil from '@/main/utils/FsUtil' -const app = electronRequire('app') - export default class EnvMacOS { static _envFileName = '.zshrc'; static getEnvFilePath() { - return Path.Join(app.getPath('home'), this._envFileName); + return Path.Join(OS.getHomeDir(), this._envFileName); } static async switch(enable) { diff --git a/src/main/core/Nginx.js b/src/main/core/Nginx.js index 2229e2e4..31212795 100644 --- a/src/main/core/Nginx.js +++ b/src/main/core/Nginx.js @@ -106,8 +106,8 @@ export default class Nginx { access_log off; } - access_log logs/${Path.GetFileNameWithoutExtension(confName)}.access.log; - error_log logs/${Path.GetFileNameWithoutExtension(confName)}.error.log; + access_log logs/${Path.GetFileNameWithoutExt(confName)}.access.log; + error_log logs/${Path.GetFileNameWithoutExt(confName)}.error.log; }`; confText = replaceLineBreak(confText) @@ -190,7 +190,7 @@ export default class Nginx { } let files = await DirUtil.GetFiles(rewritePath, '.conf'); return files.map(name => { - return Path.GetFileNameWithoutExtension(name); + return Path.GetFileNameWithoutExt(name); }); } @@ -213,7 +213,7 @@ export default class Nginx { * @returns {number} */ static getPortByConfPath(path){ - return Number(Path.GetFileNameWithoutExtension(path).split('_')[1]) + return Number(Path.GetFileNameWithoutExt(path).split('_')[1]) } static getErrorLogOffValue(){ diff --git a/src/main/core/php/extension/Installer.js b/src/main/core/php/extension/Installer.js index 65bb1e4b..4041ff8c 100644 --- a/src/main/core/php/extension/Installer.js +++ b/src/main/core/php/extension/Installer.js @@ -1,101 +1,101 @@ -import { isDev, isMacOS, isWindows } from '@/main/utils/utils' -import Path from '@/main/utils/Path' -import GetPath from '@/shared/utils/GetPath' -import child_process from 'child_process' -import fsPromises from 'fs/promises' -import DirUtil from '@/main/utils/DirUtil' -import fixPath from 'fix-path' -import Extension from './Extension' -import Php from '@/main/core/php/Php' - -export default class Installer { - extName; //扩展名 - extVersion - phpVersion; //php版本。如8.0 - msg; - errMsg; - eventEmitter; - constructor(extName,extVersion,phpVersion,eventEmitter) { - this.extName = extName; - this.extVersion = extVersion; - this.phpVersion = phpVersion; - this.eventEmitter = eventEmitter; - } - - /** - * - * @returns {Promise} command - */ - async install() { - if (isMacOS) { - fixPath(); - } - - let commandStr; - let phpExtDlDir = Path.Join(GetPath.getDownloadsDir(), 'phpExt'); - if (!await DirUtil.Exists(phpExtDlDir)) { - await DirUtil.Create(phpExtDlDir); - } - let phpDir = GetPath.getPhpDir(this.phpVersion); - - const scriptPath = Extension.getInstallScriptPath(this.extName); - if (isWindows) { - let extFileName = Extension.getFileName(this.extName); - let phpExtDir = await Php.getExtensionDir(this.phpVersion); - let dlFileName = this.getDownloadFileName(); - commandStr = ` powershell.exe -ExecutionPolicy Bypass -File "${scriptPath}"`; - commandStr += ` ${phpExtDlDir} ${phpDir} ${this.extVersion} ${this.extName} ${extFileName} ${phpExtDir} ${dlFileName}`; - } else { - await fsPromises.chmod(scriptPath, 0o755); - commandStr = `${scriptPath} ${phpExtDlDir} ${phpDir} ${this.extVersion}`; - } - - let childProcess = child_process.exec(commandStr); - - childProcess.stderr.on('data', (data) => { - this.eventEmitter.emit('phpExt:stderr', data.toString()) - }); - - childProcess.stdout.on('data', (data) => { - this.eventEmitter.emit('phpExt:stdout', data.toString()) - }); - - childProcess.on('exit', (code, signal) => { - this.eventEmitter.emit('phpExt:exit', code, signal) - }); - - this.eventEmitter.on('phpExt:stop', () => { - childProcess.kill(); - }) - return commandStr; - } - - stop(){ - this.eventEmitter.emit('phpExt:stop'); - } - - getDownloadFileName() { - let vcVersion = this.getVcStringVersion(); - return `php_${this.extName}-${this.extVersion}-${this.phpVersion}-nts-${vcVersion}-x64.zip`; - } - - getVcStringVersion() { - switch (this.phpVersion) { - case '8.3': - case '8.2': - case '8.1': - case '8.0': - return 'vs16'; - case '7.4': - case '7.3': - case '7.2': - return 'vc15'; - case '7.1': - case '7.0': - return 'vc14'; - case '5.6': - return 'vc11'; - } - } - -} +import { isDev, isMacOS, isWindows } from '@/main/utils/utils' +import Path from '@/main/utils/Path' +import GetPath from '@/shared/utils/GetPath' +import child_process from 'child_process' +import fsPromises from 'fs/promises' +import DirUtil from '@/main/utils/DirUtil' +import fixPath from 'fix-path' +import Extension from './Extension' +import Php from '@/main/core/php/Php' + +export default class Installer { + extName; //扩展名 + extVersion + phpVersion; //php版本。如8.0 + msg; + errMsg; + eventEmitter; + constructor(extName,extVersion,phpVersion,eventEmitter) { + this.extName = extName; + this.extVersion = extVersion; + this.phpVersion = phpVersion; + this.eventEmitter = eventEmitter; + } + + /** + * + * @returns {Promise} command + */ + async install() { + if (isMacOS) { + fixPath(); + } + + let commandStr; + let phpExtDlDir = Path.Join(GetPath.getDownloadsDir(), 'phpExt'); + if (!await DirUtil.Exists(phpExtDlDir)) { + await DirUtil.Create(phpExtDlDir); + } + let phpDir = GetPath.getPhpDir(this.phpVersion); + + const scriptPath = Extension.getInstallScriptPath(this.extName); + if (isWindows) { + let extFileName = Extension.getFileName(this.extName); + let phpExtDir = await Php.getExtensionDir(this.phpVersion); + let dlFileName = this.getDownloadFileName(); + commandStr = ` powershell.exe -ExecutionPolicy Bypass -File "${scriptPath}"`; + commandStr += ` ${phpExtDlDir} ${phpDir} ${this.extVersion} ${this.extName} ${extFileName} ${phpExtDir} ${dlFileName}`; + } else { + await fsPromises.chmod(scriptPath, 0o755); + commandStr = `${scriptPath} ${phpExtDlDir} ${phpDir} ${this.extVersion}`; + } + + let childProcess = child_process.exec(commandStr); + + childProcess.stderr.on('data', (data) => { + this.eventEmitter.emit('phpExt:stderr', data.toString()) + }); + + childProcess.stdout.on('data', (data) => { + this.eventEmitter.emit('phpExt:stdout', data.toString()) + }); + + childProcess.on('exit', (code, signal) => { + this.eventEmitter.emit('phpExt:exit', code, signal) + }); + + this.eventEmitter.on('phpExt:stop', () => { + childProcess.kill(); + }) + return commandStr; + } + + stop(){ + this.eventEmitter.emit('phpExt:stop'); + } + + getDownloadFileName() { + let vcVersion = this.getVcStringVersion(); + return `php_${this.extName}-${this.extVersion}-${this.phpVersion}-nts-${vcVersion}-x64.zip`; + } + + getVcStringVersion() { + switch (this.phpVersion) { + case '8.3': + case '8.2': + case '8.1': + case '8.0': + return 'vs16'; + case '7.4': + case '7.3': + case '7.2': + return 'vc15'; + case '7.1': + case '7.0': + return 'vc14'; + case '5.6': + return 'vc11'; + } + } + +} diff --git a/src/main/core/software/LocalInstall.js b/src/main/core/software/LocalInstall.js index 76c7d9f5..98ca1409 100644 --- a/src/main/core/software/LocalInstall.js +++ b/src/main/core/software/LocalInstall.js @@ -35,9 +35,9 @@ export default class LocalInstall { }; static getDirName(filePath) { - let dirName = Path.GetFileNameWithoutExtension(filePath); + let dirName = Path.GetFileNameWithoutExt(filePath); if (dirName.endsWith('.tar')) { - dirName = Path.GetFileNameWithoutExtension(dirName); + dirName = Path.GetFileNameWithoutExt(dirName); } return dirName; } diff --git a/src/main/core/website/NginxWebsite.js b/src/main/core/website/NginxWebsite.js index 4d8354ed..5e907776 100644 --- a/src/main/core/website/NginxWebsite.js +++ b/src/main/core/website/NginxWebsite.js @@ -27,7 +27,7 @@ export default class NginxWebsite { } async init() { - this.serverName = Path.GetFileNameWithoutExtension(this.confName).split('_')[0] + this.serverName = Path.GetFileNameWithoutExt(this.confName).split('_')[0] this.confPath = Nginx.getWebsiteConfPath(this.confName) this.confText = await FileUtil.ReadAll(this.confPath) } diff --git a/src/main/index.js b/src/main/index.js index 768f3dc6..e5d240fc 100644 --- a/src/main/index.js +++ b/src/main/index.js @@ -1,7 +1,6 @@ import { app, shell, BrowserWindow } from 'electron' import { join } from 'path' import { is } from '@electron-toolkit/utils' -import remoteMain from '@electron/remote/main' import Store from 'electron-store' import MainWindow from '@/main/MainWindow' import '@/main/ipcListen' @@ -36,7 +35,6 @@ async function createMainWindow() { nodeIntegration: true, contextIsolation: false, webSecurity: false, - nodeIntegrationInWorker: true } }) @@ -61,7 +59,6 @@ async function createMainWindow() { } else { mainWindow.loadFile(join(__dirname, '../renderer/index.html')) } - remoteMain.enable(mainWindow.webContents) MainWindow.init(mainWindow) } @@ -69,7 +66,6 @@ function onReady() { app.on('ready', async () => { createMainWindow() Store.initRenderer() - remoteMain.initialize() I18n.init() }) } diff --git a/src/main/ipcListen.js b/src/main/ipcListen.js index a30fd0a1..9b5432e2 100644 --- a/src/main/ipcListen.js +++ b/src/main/ipcListen.js @@ -1,8 +1,8 @@ -import { ipcMain } from 'electron' -import { callStatic } from '@/main/common/call' +import {app, ipcMain} from 'electron' +import {callStatic} from '@/main/common/call' import Settings from '@/main/Settings' import SystemTheme from '@/main/utils/SystemTheme' -import { color } from '@/shared/utils/constant' +import {color} from '@/shared/utils/constant' import Installer from '@/main/core/software/Installer' import Downloader from 'electron-dl-downloader' @@ -26,6 +26,29 @@ ipcMain.on('getColors', (event) => { }) const functions = { + appGetVersion: async () => { + return app.getVersion() + }, + appExit: async () => { + return app.exit() + }, + fileGetIcon: async (event, path, options) => { + return await app.getFileIcon(path, options) + }, + windowSwitchMax: async (event) => { + const win = event.sender.getOwnerBrowserWindow() + if (win.isMaximized()) { + win.unmaximize() + } else { + win.maximize() + } + }, + windowMinimize: async (event) => { + event.sender.getOwnerBrowserWindow().minimize() + }, + windowClose: async (event) => { + event.sender.getOwnerBrowserWindow().close() + }, softwareInstall: async (event, name) => { const installer = new Installer(name) installer.on('status', (status) => { @@ -35,7 +58,7 @@ const functions = { const dlItem = await installer.install() dlItem.on('updated', (event2, state) => { if (state === Downloader.STATES.progressing) { - const progress = { receivedBytes: dlItem.getReceivedBytes(), totalBytes: dlItem.getTotalBytes() } + const progress = {receivedBytes: dlItem.getReceivedBytes(), totalBytes: dlItem.getTotalBytes()} event.sender.send('software-downloadProgress', name, progress) } else { event.sender.send('software-downloadCancelled', name) diff --git a/src/main/utils/FileDialog.js b/src/main/utils/FileDialog.js index 03454102..0d628d3c 100644 --- a/src/main/utils/FileDialog.js +++ b/src/main/utils/FileDialog.js @@ -1,63 +1,62 @@ -import { electronRequire } from '@/main/utils/electron' -import { isMacOS, isWindows } from '@/main/utils/utils' - -const dialog = electronRequire('dialog') - -export default class FileDialog { - static showOpenDirectory(defaultPath = null) { - let options = { - properties: ['openDirectory'] - } - if (defaultPath) { - if (isWindows) { - defaultPath = defaultPath.replaceAll("/", "\\"); - } - options.defaultPath = defaultPath; - } - let res = dialog.showOpenDialogSync(options); - return res ? res[0] : null; - } - - static showOpenFile(defaultPath = null, filters = []) { - let options = { - properties: ['openFile'], - filters - } - if (defaultPath) { - if (isWindows) { - defaultPath = defaultPath.replaceAll('/', '\\') - } - options.defaultPath = defaultPath - } - let res = dialog.showOpenDialogSync(options) - return res ? res[0] : null - } - - static showOpenApp(defaultPath = null) { - let filters; - if (isWindows) { - filters = [{name: '应用程序', extensions: ['exe']}]; - } - if (isMacOS) { - filters = [{name: '应用程序', extensions: ['app']}]; - } - let options = { - properties: ['openFile'], - filters: filters - } - if (defaultPath) { - if (isWindows) { - defaultPath = defaultPath.replaceAll('/', '\\') - } - options.defaultPath = defaultPath; - }else { - if(isMacOS){ - options.defaultPath = '/Applications'; - } - } - let res = dialog.showOpenDialogSync(options); - return res ? res[0] : null; - } -} - - +import { dialog } from 'electron' +import { isMacOS, isWindows } from '@/main/utils/utils' +import MainWindow from "@/main/MainWindow"; + +export default class FileDialog { + static showOpenDirectory(defaultPath = null) { + let options = { + properties: ['openDirectory'] + } + if (defaultPath) { + if (isWindows) { + defaultPath = defaultPath.replaceAll("/", "\\"); + } + options.defaultPath = defaultPath; + } + let res = dialog.showOpenDialogSync(MainWindow.getInstance(),options); + return res ? res[0] : null; + } + + static showOpenFile(defaultPath = null, filters = []) { + let options = { + properties: ['openFile'], + filters + } + if (defaultPath) { + if (isWindows) { + defaultPath = defaultPath.replaceAll('/', '\\') + } + options.defaultPath = defaultPath + } + let res = dialog.showOpenDialogSync(MainWindow.getInstance(),options) + return res ? res[0] : null + } + + static showOpenApp(defaultPath = null) { + let filters; + if (isWindows) { + filters = [{name: '应用程序', extensions: ['exe']}]; + } + if (isMacOS) { + filters = [{name: '应用程序', extensions: ['app']}]; + } + let options = { + properties: ['openFile'], + filters: filters + } + if (defaultPath) { + if (isWindows) { + defaultPath = defaultPath.replaceAll('/', '\\') + } + options.defaultPath = defaultPath; + }else { + if(isMacOS){ + options.defaultPath = '/Applications'; + } + } + let res = dialog.showOpenDialogSync(MainWindow.getInstance(),options); + return res ? res[0] : null; + } +} + + diff --git a/src/main/utils/GetAppPath.js b/src/main/utils/GetAppPath.js index a76704ce..4b664bdf 100644 --- a/src/main/utils/GetAppPath.js +++ b/src/main/utils/GetAppPath.js @@ -1,21 +1,18 @@ import { isDev, isMacOS, isWindows } from '@/main/utils/utils' -import path from 'path' -import { electronRequire } from '@/main/utils/electron' import { INIT_FILE_NAME, MAC_CORE_PATH_NAME, MAC_USER_CORE_DIR, WIN_CORE_PATH_NAME } from '@/main/utils/constant' - -const app = electronRequire('app') +import Path from '@/main/utils/Path' export default class GetAppPath { static getDir() { if (isDev) { - return app.getAppPath() + return process.cwd() } else { - return path.dirname(this.getExePath()) + return Path.GetDirName(this.getExePath()) } } @@ -24,7 +21,7 @@ export default class GetAppPath { * @returns {string} */ static getExePath() { - return app.getPath('exe') + return process.execPath //同app.getPath('exe') } /** @@ -35,15 +32,15 @@ export default class GetAppPath { let result = '' if (isWindows) { if (isDev) { - result = path.join(this.getDevPlatformDir(), WIN_CORE_PATH_NAME) + result = Path.Join(this.getDevPlatformDir(), WIN_CORE_PATH_NAME) } else { - result = path.join(this.getDir(), WIN_CORE_PATH_NAME) + result = Path.Join(this.getDir(), WIN_CORE_PATH_NAME) } } else if (isMacOS) { if (isDev) { - result = path.join(this.getDevPlatformDir(), MAC_CORE_PATH_NAME) + result = Path.Join(this.getDevPlatformDir(), MAC_CORE_PATH_NAME) } else { - result = path.join(this.getContentsDir(), MAC_CORE_PATH_NAME) + result = Path.Join(this.getContentsDir(), MAC_CORE_PATH_NAME) } } return result @@ -66,7 +63,7 @@ export default class GetAppPath { */ static getContentsDir() { if (isMacOS) { - return path.join(this.getDir(), '..') + return Path.Join(this.getDir(), '..') } return '' } @@ -75,20 +72,11 @@ export default class GetAppPath { return this.getUserCoreDir() } - static getFrontEndDir() { - return app.getAppPath() - } - - static getStaticDir() { - //这里的resources是指项目resources目录,非electron resources目录 - return path.join(this.getFrontEndDir(), 'resources') - } - static getDevPlatformDir() { - return path.join(this.getDir(), `extra/${process.platform}`) + return Path.Join(this.getDir(), `extra/${process.platform}`) } static getInitFilePath() { - return path.join(this.getCoreDir(), INIT_FILE_NAME) + return Path.Join(this.getCoreDir(), INIT_FILE_NAME) } } diff --git a/src/main/utils/Native.js b/src/main/utils/Native.js index 64249522..3e555adf 100644 --- a/src/main/utils/Native.js +++ b/src/main/utils/Native.js @@ -1,4 +1,3 @@ -import { electronRequire } from '@/main/utils/electron' import Shell from '@/main/utils/Shell' import MessageBox from '@/renderer/utils/MessageBox' import fixPath from 'fix-path' @@ -8,8 +7,7 @@ import Settings from '@/main/Settings' import { isMacOS, isWindows } from '@/main/utils/utils' import FsUtil from '@/main/utils/FsUtil' import { t } from '@/renderer/utils/i18n' - -const shell = electronRequire('shell') +const { shell } = require('electron') export default class Native { /** diff --git a/src/main/utils/OS.js b/src/main/utils/OS.js index 9cb912ff..1cfc3bbf 100644 --- a/src/main/utils/OS.js +++ b/src/main/utils/OS.js @@ -1,63 +1,67 @@ -import os from 'os' -import process from 'process' -import { PowerShell } from '@/main/utils/constant' -import { isWindows } from '@/main/utils/utils' -import util from 'util' -import child_process from 'child_process' - -export default class OS { - static _majorVersion = null - static _simpleLanguage = null - - /** - * 获取系统版本号字符串,Windows如10.0.19045 - * @returns {string} - */ - static getVersion() { - return os.release() - } - - /** - * 获取系统主要版本号,Windows如10 - * @returns {number} - */ - static getMajorVersion() { - this._majorVersion = this._majorVersion ? this._majorVersion : Number(this.getVersion().split('.')[0]) - return this._majorVersion - } - - static getUserName() { - return os.userInfo().username - } - - static isMacOS() { - return process.platform === 'darwin' - } - - static isWindows() { - return process.platform === 'win32' - } - - /** - * 获取系统当前的语言,如zh、en等; - * @returns {Promise} - */ - static async getSimpleLanguage() { - if (this._simpleLanguage) return this._simpleLanguage - if (isWindows) { - this._simpleLanguage = await this.getSimpleLanguageForWindows() - } - return this._simpleLanguage - } - - - static async getSimpleLanguageForWindows() { - const exec = util.promisify(child_process.exec) - try { - const { stdout } = await exec('(Get-Culture).TwoLetterISOLanguageName', { shell: PowerShell }) - return stdout.trim() - } catch (error) { - return '' - } - } -} +import os from 'os' +import process from 'process' +import { PowerShell } from '@/main/utils/constant' +import { isWindows } from '@/main/utils/utils' +import util from 'util' +import child_process from 'child_process' + +export default class OS { + static _majorVersion = null + static _simpleLanguage = null + + /** + * 获取系统版本号字符串,Windows如10.0.19045 + * @returns {string} + */ + static getVersion() { + return os.release() + } + + /** + * 获取系统主要版本号,Windows如10 + * @returns {number} + */ + static getMajorVersion() { + this._majorVersion = this._majorVersion ? this._majorVersion : Number(this.getVersion().split('.')[0]) + return this._majorVersion + } + + static getHomeDir() { + return os.homedir() + } + + static getUserName() { + return os.userInfo().username + } + + static isMacOS() { + return process.platform === 'darwin' + } + + static isWindows() { + return process.platform === 'win32' + } + + /** + * 获取系统当前的语言,如zh、en等; + * @returns {Promise} + */ + static async getSimpleLanguage() { + if (this._simpleLanguage) return this._simpleLanguage + if (isWindows) { + this._simpleLanguage = await this.getSimpleLanguageForWindows() + } + return this._simpleLanguage + } + + + static async getSimpleLanguageForWindows() { + const exec = util.promisify(child_process.exec) + try { + const { stdout } = await exec('(Get-Culture).TwoLetterISOLanguageName', { shell: PowerShell }) + return stdout.trim() + } catch (error) { + return '' + } + } +} diff --git a/src/main/utils/Path.js b/src/main/utils/Path.js index 22548828..6fe94f48 100644 --- a/src/main/utils/Path.js +++ b/src/main/utils/Path.js @@ -1,51 +1,51 @@ -import nodePath from 'path' - -export default class Path { - /** - * 获取目录的最后一部分 - * @param path {string} - * @returns {string} - */ - static GetBaseName(path) { - return nodePath.basename(path) - } - - /** - * 获取文件名,不带扩展名 - * @param path {string} - * @returns {string} - */ - static GetFileNameWithoutExtension(path) { - return nodePath.parse(path).name - } - - /** - * 获取文件扩展名 - * @param path {string} - * @returns {string} - */ - static GetExtension(path) { - return nodePath.extname(path) - } - - /** - * 获取目录名 - * @param path {string} - * @returns {string} - */ - static GetDirectoryName(path) { - return nodePath.dirname(path) - } - - static Resolve(...path) { - return nodePath.resolve(...path) - } - - static Combine(...path) { - return this.Resolve(...path) - } - - static Join(...path) { - return nodePath.join(...path) - } -} +import nodePath from 'path' + +export default class Path { + /** + * 获取目录的最后一部分 + * @param path {string} + * @returns {string} + */ + static GetBaseName(path) { + return nodePath.basename(path) + } + + /** + * 获取文件名,不带扩展名 + * @param path {string} + * @returns {string} + */ + static GetFileNameWithoutExt(path) { + return nodePath.parse(path).name + } + + /** + * 获取文件扩展名 + * @param path {string} + * @returns {string} + */ + static GetExt(path) { + return nodePath.extname(path) + } + + /** + * 获取目录名 + * @param path {string} + * @returns {string} + */ + static GetDirName(path) { + return nodePath.dirname(path) + } + + static Resolve(...path) { + return nodePath.resolve(...path) + } + + static Combine(...path) { + return this.Resolve(...path) + } + + static Join(...path) { + return nodePath.join(...path) + } +} diff --git a/src/main/utils/SystemTheme.js b/src/main/utils/SystemTheme.js index ab179ab8..2f3ecb4b 100644 --- a/src/main/utils/SystemTheme.js +++ b/src/main/utils/SystemTheme.js @@ -1,14 +1,10 @@ -import { electronRequire } from '@/main/utils/electron' - -const nativeTheme = electronRequire('nativeTheme') -const systemPreferences = electronRequire('systemPreferences') export default class SystemTheme { static isDarkModel() { - return nativeTheme.shouldUseDarkColors; + if (process.type === 'renderer') { + return window.matchMedia('(prefers-color-scheme: dark)').matches + } else { + const { nativeTheme } = require('electron') + return nativeTheme.shouldUseDarkColors + } } - - static getColor(){ - return systemPreferences.getAccentColor(); - } - } diff --git a/src/main/utils/TcpProcess.js b/src/main/utils/TcpProcess.js index 1065d90a..233d4408 100644 --- a/src/main/utils/TcpProcess.js +++ b/src/main/utils/TcpProcess.js @@ -1,13 +1,10 @@ -import { electronRequire } from '@/main/utils/electron' import Shell from '@/main/utils/Shell' import ProcessExtend from '@/main/utils/ProcessExtend' import { isMacOS, isWindows } from '@/main/utils/utils' import { PowerShell } from '@/main/utils/constant' - -const app = electronRequire('app') +import { getFileIcon } from '@/shared/utils/file' export default class TcpProcess { - static async getList() { if (isMacOS) { return await this.getListForMacOS() @@ -18,30 +15,30 @@ export default class TcpProcess { } static async getListForMacOS() { - let commandStr = `lsof -iTCP -sTCP:LISTEN -P -n|awk 'NR!=1{print $1,$2,$3,$5,$9}'`; + let commandStr = `lsof -iTCP -sTCP:LISTEN -P -n|awk 'NR!=1{print $1,$2,$3,$5,$9}'` try { - let resStr = await Shell.sudoExec(commandStr); - resStr = resStr.trim(); + let resStr = await Shell.sudoExec(commandStr) + resStr = resStr.trim() if (!resStr) { - return []; + return [] } - let list = resStr.split('\n'); + let list = resStr.split('\n') return await Promise.all( - list.map(async line => { - let lineArr = line.split(' '); - let name, pid, user, type, ipAndPort; - [name, pid, user, type, ipAndPort] = lineArr; - let tempArr = ipAndPort.match(/^(.*):(\d+)$/); - let ip, port; - [, ip, port] = tempArr + list.map(async (line) => { + let lineArr = line.split(' ') + let name, pid, user, type, ipAndPort + ;[name, pid, user, type, ipAndPort] = lineArr + let tempArr = ipAndPort.match(/^(.*):(\d+)$/) + let ip, port + ;[, ip, port] = tempArr const path = await ProcessExtend.getPathByPid(pid) return { name, pid, user, type, ip, port, path, status: 'Listen' } }) - ); + ) } catch (e) { - return []; + return [] } } @@ -59,16 +56,16 @@ export default class TcpProcess { let list = resStr.split(/\r?\n\r?\n/) return await Promise.all( - list.map(async item => { + list.map(async (item) => { let lineArr = item.split(/r?\n/) - let arr = lineArr.map(line => { + let arr = lineArr.map((line) => { return line.split(' : ')[1]?.trim() }) - let pid, ip, port, name, path; - [pid, ip, port, name, path] = arr + let pid, ip, port, name, path + ;[pid, ip, port, name, path] = arr - let icon = path ? (await app.getFileIcon(path))?.toDataURL() : null + let icon = path ? await getFileIcon(path) : null return { pid, ip, port, name, path, status: 'Listen', icon } }) ) @@ -89,7 +86,7 @@ export default class TcpProcess { const { pid, ip, port } = item const name = await hmc.getProcessName2(pid) const path = await ProcessExtend.getPathByPid(pid) - const icon = path ? (await app.getFileIcon(path))?.toDataURL() : null + const icon = path ? await getFileIcon(path) : null result.push({ pid, ip, port, name, path, status: 'Listen', icon }) } diff --git a/src/main/utils/electron.js b/src/main/utils/electron.js deleted file mode 100644 index f46c1859..00000000 --- a/src/main/utils/electron.js +++ /dev/null @@ -1,16 +0,0 @@ - -export function electronRequire(module) { - if (process.type === 'renderer') { - return require('@electron/remote')[module] - } else { - return require('electron')[module] - } -} - -export function electronRequireMulti() { - if (process.type === 'renderer') { - return require('@electron/remote') - } else { - return require('electron') - } -} diff --git a/src/main/utils/utils.js b/src/main/utils/utils.js index 90178b65..4a71ea58 100644 --- a/src/main/utils/utils.js +++ b/src/main/utils/utils.js @@ -1,22 +1,21 @@ -import { electronRequire } from '@/main/utils/electron' -import OS from '@/main/utils/OS' - -const app = electronRequire('app') - - -export const isDev = !app.isPackaged -export const isWindows = OS.isWindows(); -export const isMacOS = OS.isMacOS(); -export function devConsoleLog(...str) { - if (isDev) { - console.log(...str) - } -} - -export function replaceLineBreak(str) { - if (isWindows) { - return str.replaceAll('\n', '\r\n') - } else { - return str.replaceAll('\r\n', '\n') - } -} +import { sep } from 'path' +import OS from '@/main/utils/OS' + +export const isDev = process.resourcesPath.includes(`${sep}node_modules${sep}`) + +export const isWindows = OS.isWindows() +export const isMacOS = OS.isMacOS() + +export function devConsoleLog(...str) { + if (isDev) { + console.log(...str) + } +} + +export function replaceLineBreak(str) { + if (isWindows) { + return str.replaceAll('\n', '\r\n') + } else { + return str.replaceAll('\r\n', '\n') + } +} diff --git a/src/preload/index.js b/src/preload/index.js index 26d150bd..fda27dd8 100644 --- a/src/preload/index.js +++ b/src/preload/index.js @@ -1,29 +1,31 @@ -import { contextBridge, ipcRenderer } from 'electron' -import { electronAPI } from '@electron-toolkit/preload' - -// Custom APIs for renderer -const api = { - call: async (funName, ...args) => { - return await ipcRenderer.invoke('call', funName, ...args) - }, - callStatic: async (className, methodName, ...args) => { - return await ipcRenderer.invoke('callStatic', className, methodName, ...args) - }, - onSoftDlProgress: (callback) => ipcRenderer.on('software-downloadProgress', (_event, ...args) => callback(...args)), - onSoftDlCancelled: (callback) => ipcRenderer.on('software-downloadCancelled', (_event, ...args) => callback(...args)), - onSoftInstStatus: (callback) => ipcRenderer.on('software-installStatus', (_event, ...args) => callback(...args)) -} -// Use `contextBridge` APIs to expose Electron APIs to -// renderer only if context isolation is enabled, otherwise -// just add to the DOM global. -if (process.contextIsolated) { - try { - contextBridge.exposeInMainWorld('electron', electronAPI) - contextBridge.exposeInMainWorld('api', api) - } catch (error) { - console.error(error) - } -} else { - window.electron = electronAPI - window.api = api -} +import { contextBridge, ipcRenderer } from 'electron' +import { electronAPI } from '@electron-toolkit/preload' + +// Custom APIs for renderer +const api = { + call: async (funName, ...args) => { + return await ipcRenderer.invoke('call', funName, ...args) + }, + callStatic: async (className, methodName, ...args) => { + return await ipcRenderer.invoke('callStatic', className, methodName, ...args) + }, + onMainWindowMaximize: (callback) => ipcRenderer.on('mainWindowMaximize', (_event, ...args) => callback(...args)), + onMainWindowUnmaximize: (callback) => ipcRenderer.on('mainWindowUnmaximize', (_event, ...args) => callback(...args)), + onSoftDlProgress: (callback) => ipcRenderer.on('software-downloadProgress', (_event, ...args) => callback(...args)), + onSoftDlCancelled: (callback) => ipcRenderer.on('software-downloadCancelled', (_event, ...args) => callback(...args)), + onSoftInstStatus: (callback) => ipcRenderer.on('software-installStatus', (_event, ...args) => callback(...args)) +} +// Use `contextBridge` APIs to expose Electron APIs to +// renderer only if context isolation is enabled, otherwise +// just add to the DOM global. +if (process.contextIsolated) { + try { + contextBridge.exposeInMainWorld('electron', electronAPI) + contextBridge.exposeInMainWorld('api', api) + } catch (error) { + console.error(error) + } +} else { + window.electron = electronAPI + window.api = api +} diff --git a/src/renderer/App.vue b/src/renderer/App.vue index 641f98c4..7caa61ee 100644 --- a/src/renderer/App.vue +++ b/src/renderer/App.vue @@ -45,7 +45,7 @@ const userPwdModalShow = ref(false) const setLanguageShow = ref(false) const serverReactive = reactive({ restartFn: undefined, startPhpFpmFn: undefined }) - +const call = window.api.call provide('GlobalProvide', { serverReactive }) const settings = Settings.getAll() @@ -66,7 +66,7 @@ onMounted(async () => { await changeLanguageWrapper(store.settings.Language) } catch (error) { await MessageBox.error(error.message ?? error, t('errorOccurredDuring', [t('initializing')])) - App.exit() + await call('appExit') } if (isWindows) { @@ -77,7 +77,7 @@ onMounted(async () => { async function initOrUpdate() { if (isMacOS && process.arch === 'arm64' && !(await SystemExtend.isInstallRosetta())) { await MessageBox.error(`需要Rosetta支持,请复制命令到终端执行安装\nsoftwareupdate --install-rosetta`) - App.exit() + await call('appExit') } //存在initFile文件的情况下,判断是第一次安装,还是覆盖安装 if (!(await Software.DirExists())) { @@ -110,7 +110,7 @@ async function winInit() { store.loading = false } catch (error) { await MessageBox.error(error.message ?? error, t('errorOccurredDuring', [t('initializing')])) - App.exit() + await call('appExit') } } @@ -121,7 +121,7 @@ async function macCreateUserCoreDir() { } } catch (error) { await MessageBox.error(error.message ?? error, t('errorOccurredDuring', [t('initializing')])) - App.exit() + await call('appExit') } } @@ -133,7 +133,7 @@ async function update() { store.loading = false } catch (error) { await MessageBox.error(error.message ?? error, t('errorOccurredDuring', [t('update')])) - App.exit() + await call('appExit') } } diff --git a/src/renderer/components/Input/InputOpenDirDialog.vue b/src/renderer/components/Input/InputOpenDirDialog.vue index 48b55be5..7dd5c65f 100644 --- a/src/renderer/components/Input/InputOpenDirDialog.vue +++ b/src/renderer/components/Input/InputOpenDirDialog.vue @@ -1,42 +1,38 @@ - - - - - - + + + + + diff --git a/src/renderer/components/Input/InputOpenFileDialog.vue b/src/renderer/components/Input/InputOpenFileDialog.vue index e49f2266..cb50683c 100644 --- a/src/renderer/components/Input/InputOpenFileDialog.vue +++ b/src/renderer/components/Input/InputOpenFileDialog.vue @@ -11,7 +11,7 @@ + + + + + diff --git a/src/renderer/components/Theme/ConfigProvider.vue b/src/renderer/components/Theme/ConfigProvider.vue index 7f84e09e..492a94f9 100644 --- a/src/renderer/components/Theme/ConfigProvider.vue +++ b/src/renderer/components/Theme/ConfigProvider.vue @@ -9,15 +9,13 @@ import TokenProvider from '@/renderer/components/Theme/TokenProvider.vue' import { useMainStore } from '@/renderer/store' -import { electronRequire } from '@/main/utils/electron' -const nativeTheme = electronRequire('nativeTheme') const store = useMainStore() -nativeTheme.on('updated', () => { +window.matchMedia('(prefers-color-scheme: dark)').onchange = () => { if (store.settings.ThemeMode === 'system') { store.changeTheme(store.settings.ThemeMode, store.settings.ThemeColor) } -}) +} + + + + + diff --git a/src/renderer/components/UserPwdModal.vue b/src/renderer/components/UserPwdModal.vue index c17958ac..e56d0f54 100644 --- a/src/renderer/components/UserPwdModal.vue +++ b/src/renderer/components/UserPwdModal.vue @@ -25,7 +25,7 @@ import SystemExtend from '@/main/utils/SystemExtend' import MessageBox from '@/renderer/utils/MessageBox' import { useMainStore } from '@/renderer/store' import { mt, t } from '@/renderer/utils/i18n' - +const call = window.api.call const store = useMainStore() const props = defineProps({ @@ -79,7 +79,7 @@ const saveUserPwd = async () => { store.loading = false; } catch (error) { await MessageBox.error(error.message ?? error,t('errorOccurredDuring', [t('initializing')])); - App.exit(); + await call('appExit') } } okButtonLoading.value = false; @@ -87,9 +87,9 @@ const saveUserPwd = async () => { const cancel = () => { if (props.cancelIsExit) { - App.exit(); + call('appExit') } else { - visible.value = false; + visible.value = false } } diff --git a/src/renderer/views/About.vue b/src/renderer/views/About.vue index dfa8c96c..666c4af5 100644 --- a/src/renderer/views/About.vue +++ b/src/renderer/views/About.vue @@ -17,12 +17,15 @@