diff --git a/go-client/config.json b/go-client/config.json index 2d79ca7..b0777c7 100644 --- a/go-client/config.json +++ b/go-client/config.json @@ -161,13 +161,171 @@ ] }, "macos": { - "terminal": [], - "remotedesktop": [], - "databases": [] + "terminal": [ + { + "name": "terminal", + "display_name": "Terminal", + "protocol": [ + "ssh" + ], + "comment": "Terminal是MacOS操作系统上的虚拟终端应用软件,位于“实用工具”文件夹内。", + "download_url": "内置", + "type": "linux", + "path": "Terminal", + "arg_format": "-{protocol} {username}@{host} -P {port} -pw {value}", + "match_first": [], + "is_internal": true, + "is_default": true, + "is_set": true + }, + { + "name": "securecrt", + "display_name": "SecureCRT", + "protocol": [ + "ssh" + ], + "comment": "SecureCRT是VanDyke Software所开发销售的一个SSH、Telnet客户端和虚拟终端软件。\n\n!!!手动下载安装,点击保存启用!!!", + "download_url": "https://www.vandyke.com/cgi-bin/releases.php?product=securecrt", + "type": "linux", + "path": "/Applications/SecureCRT.app/Contents/MacOS/SecureCRT", + "arg_format": "/N {name} /T /SSH2 /ACCEPTHOSTKEYS /p {port} /password {value} /L {username} {host}", + "match_first": [], + "is_internal": false, + "is_default": false, + "is_set": false + } + ], + "remotedesktop": [ + { + "name": "mstsc", + "display_name": "Microsoft Remote Desktop", + "protocol": [ + "rdp" + ], + "comment": "Microsoft Remote Desktop是一款强大的微软远程连接工具,可以从几乎任何地方连接到远程PC和您的工作资源。\n\n!!!手动下载安装,点击保存启用!!!", + "download_url": "内置", + "type": "windows", + "path": "/Applications/Microsoft Remote Desktop.app", + "arg_format": "", + "match_first": [], + "is_internal": true, + "is_default": true, + "is_set": false + } + ], + "filetransfer": [ + { + "name": "filezilla", + "display_name": "Filezilla", + "protocol": [ + "sftp" + ], + "comment": "FileZilla Client是一款免费、开源的 FTP 客户端。它支持FTP、SFTP。\n\n!!!手动下载安装,点击保存启用!!!", + "download_url": "https://filezilla-project.org/download.php?type=client", + "type": "linux", + "path": "/Applications/FileZilla.app/Contents/MacOS/filezilla", + "arg_format": "{protocol}://{username}:{value}@{host}:{port}", + "match_first": [], + "is_internal": false, + "is_default": false, + "is_set": false + } + ], + "databases": [ + { + "name": "dbeaver", + "display_name": "DBeaver Community", + "protocol": [ + "oracle", + "mysql", + "postgresql", + "mariadb" + ], + "comment": "DBeaver Community是一个通用的数据库管理工具和SQL客户端,支持MySQL、PostgreSQL、Oracle以及其他兼容JDBC的数据库。\n\n!!!手动下载安装,点击保存启用!!!", + "download_url": "https://dbeaver.io/download/", + "type": "databases", + "path": "/Applications/DBeaver.app/Contents/MacOS/dbeaver", + "arg_format": "-con name={name}|driver={protocol}|user={username}|password={value}|database={dbname}|host={host}|port={port}|save=false|connect=true", + "match_first": [], + "is_internal": false, + "is_default": false, + "is_set": false + } + ] }, "linux": { - "terminal": [], - "remotedesktop": [], - "databases": [] + "terminal": [ + { + "name": "terminal", + "display_name": "Terminal", + "protocol": [ + "ssh" + ], + "comment": "Terminal是MacOS操作系统上的虚拟终端应用软件,位于“实用工具”文件夹内。", + "download_url": "内置", + "type": "linux", + "path": "Terminal", + "arg_format": "-{protocol} {username}@{host} -P {port} -pw {value}", + "match_first": [], + "is_internal": true, + "is_default": true, + "is_set": true + } + ], + "remotedesktop": [ { + "name": "remmina", + "display_name": "Remmina", + "protocol": [ + "rdp" + ], + "comment": "Remmina 是一个使用 GTK+ 开发的远程桌面客户端,提供了 RDP、VNC、XDMCP、SSH 等远程连接协议的支持。", + "download_url": "https://remmina.org/how-to-install-remmina/-内置", + "type": "windows", + "path": "remmina", + "arg_format": "", + "match_first": [], + "is_internal": true, + "is_default": true, + "is_set": true + }], + "filetransfer": [ + { + "name": "filezilla", + "display_name": "Filezilla", + "protocol": [ + "sftp" + ], + "comment": "FileZilla Client是一款免费、开源的 FTP 客户端。它支持FTP、SFTP。", + "download_url": "https://filezilla-project.org/download.php?type=client", + "type": "linux", + "path": "", + "arg_format": "{protocol}://{username}:{value}@{host}:{port}", + "match_first": [], + "is_internal": false, + "is_default": false, + "is_set": false + } + ], + "databases": [ + { + "name": "dbeaver", + "display_name": "DBeaver Community", + "protocol": [ + "oracle", + "mysql", + "postgresql", + "mariadb" + ], + "comment": "DBeaver Community是一个通用的数据库管理工具和SQL客户端,支持MySQL、PostgreSQL、Oracle以及其他兼容JDBC的数据库。", + "download_url": "https://dbeaver.io/download/", + "type": "databases", + "path": "", + "arg_format": "-con name={name}|driver={protocol}|user={username}|password={value}|database={dbname}|host={host}|port={port}|save=false|connect=true", + "match_first": [], + "is_internal": false, + "is_default": false, + "is_set": false + } + ] } -} \ No newline at end of file +} diff --git a/go-client/pkg/awaken/awaken.go b/go-client/pkg/awaken/awaken.go index 236a11c..1b1d947 100755 --- a/go-client/pkg/awaken/awaken.go +++ b/go-client/pkg/awaken/awaken.go @@ -80,16 +80,7 @@ func (r *Rouse) HandleSSH(appConfig *config.AppConfig) { } func (r *Rouse) HandleDB(appConfig *config.AppConfig) { - command := r.Command - switch r.Protocol { - case "mysql", "mariadb": - command = structureMySQLCommand(command) - case "postgresql": - command = structurePostgreSQLCommand(command) - case "redis": - command = structureRedisCommand(command) - } - cmd := handleDB(r, command, appConfig) + cmd := handleDB(r, appConfig) cmd.Run() } diff --git a/go-client/pkg/awaken/awaken_darwin.go b/go-client/pkg/awaken/awaken_darwin.go index 3a65209..afab831 100755 --- a/go-client/pkg/awaken/awaken_darwin.go +++ b/go-client/pkg/awaken/awaken_darwin.go @@ -3,19 +3,95 @@ package awaken import ( "fmt" "go-client/global" + "go-client/pkg/config" "os/exec" + "path/filepath" + "strconv" + "strings" ) +func getCommandFromArgs(connectInfo map[string]string, argFormat string) string { + for key, value := range connectInfo { + argFormat = strings.Replace(argFormat, "{"+key+"}", value, 1) + } + return argFormat +} + func awakenRDPCommand(filePath string) *exec.Cmd { global.LOG.Debug(filePath) cmd := exec.Command("open", filePath) return cmd } -func awakenCommand(command string) *exec.Cmd { - cmd := exec.Command( - "osascript", "-s", "h", "-e", - fmt.Sprintf(`tell application "Terminal" to do script "%s"`, command), - ) +func awakenSSHCommand(r *Rouse, currentPath string, cfg *config.AppConfig) *exec.Cmd { + var appItem *config.AppItem + var appLst []config.AppItem + switch r.Protocol { + case "ssh": + appLst = cfg.MacOS.Terminal + case "sftp": + appLst = cfg.MacOS.FileTransfer + } + + for _, app := range appLst { + if app.IsActive() && app.IsSupportProtocol(r.Protocol) { + appItem = &app + break + } + } + if appItem == nil { + return nil + } + var cmd *exec.Cmd + if appItem.IsInternal { + clientPath := filepath.Join(currentPath, "client") + command := fmt.Sprintf("%s %s -P %s", clientPath, r.Command, r.Value) + cmd = exec.Command( + "osascript", "-s", "h", + "-e", fmt.Sprintf(`tell application "%s" to do script "%s"`, appItem.DisplayName, command), + ) + } else { + var appPath string + appPath = appItem.Path + + connectMap := map[string]string{ + "name": r.Name, + "protocol": r.Protocol, + "username": r.Username, + "value": r.Value, + "host": r.Host, + "port": strconv.Itoa(r.Port), + } + commands := getCommandFromArgs(connectMap, appItem.ArgFormat) + appPath = appItem.Path + cmd = exec.Command(appPath, strings.Split(commands, " ")...) + } return cmd } + +func awakenDBCommand(r *Rouse, cfg *config.AppConfig) *exec.Cmd { + var appItem *config.AppItem + appLst := cfg.MacOS.Databases + for _, app := range appLst { + if app.IsSet && app.IsMatchProtocol(r.Protocol) { + appItem = &app + break + } + } + if appItem == nil { + return nil + } + appPath := appItem.Path + + connectMap := map[string]string{ + "name": r.Name, + "protocol": r.Protocol, + "username": r.Username, + "value": r.Value, + "host": r.Host, + "port": strconv.Itoa(r.Port), + "dbname": r.DBName, + } + commands := getCommandFromArgs(connectMap, appItem.ArgFormat) + return exec.Command(appPath, strings.Split(commands, " ")...) +} diff --git a/go-client/pkg/awaken/awaken_linux.go b/go-client/pkg/awaken/awaken_linux.go index 5cc8497..7e8ad89 100755 --- a/go-client/pkg/awaken/awaken_linux.go +++ b/go-client/pkg/awaken/awaken_linux.go @@ -3,17 +3,29 @@ package awaken import ( "fmt" "go-client/global" + "go-client/pkg/config" "os/exec" + "path/filepath" + "strconv" "strings" ) +func getCommandFromArgs(connectInfo map[string]string, argFormat string) string { + for key, value := range connectInfo { + argFormat = strings.Replace(argFormat, "{"+key+"}", value, 1) + } + return argFormat +} + func awakenRDPCommand(filePath string) *exec.Cmd { global.LOG.Debug(filePath) cmd := exec.Command("remmina", filePath) return cmd } -func awakenCommand(command string) *exec.Cmd { +func awakenSSHCommand(r *Rouse, currentPath string, cfg *config.AppConfig) *exec.Cmd { + clientPath := filepath.Join(currentPath, "client") + command := fmt.Sprintf("%s %s -P %s", clientPath, r.Command, r.Value) cmd := new(exec.Cmd) out, _ := exec.Command("bash", "-c", "echo $XDG_CURRENT_DESKTOP").CombinedOutput() currentDesktop := strings.ToLower(strings.Trim(string(out), "\n")) @@ -32,3 +44,30 @@ func awakenCommand(command string) *exec.Cmd { } return cmd } + +func awakenDBCommand(r *Rouse, cfg *config.AppConfig) *exec.Cmd { + var appItem *config.AppItem + appLst := cfg.Windows.Databases + for _, app := range appLst { + if app.IsSet && app.IsMatchProtocol(r.Protocol) { + appItem = &app + break + } + } + if appItem == nil { + return nil + } + appPath := appItem.Path + + connectMap := map[string]string{ + "name": r.Name, + "protocol": r.Protocol, + "username": r.Username, + "value": r.Value, + "host": r.Host, + "port": strconv.Itoa(r.Port), + "dbname": r.DBName, + } + commands := getCommandFromArgs(connectMap, appItem.ArgFormat) + return exec.Command(appPath, strings.Split(commands, " ")...) +} diff --git a/go-client/pkg/awaken/awaken_unix.go b/go-client/pkg/awaken/awaken_unix.go index d68217a..47a894c 100755 --- a/go-client/pkg/awaken/awaken_unix.go +++ b/go-client/pkg/awaken/awaken_unix.go @@ -4,11 +4,8 @@ package awaken import ( - "fmt" "go-client/pkg/config" "os/exec" - "path/filepath" - "strings" ) func handleRDP(r *Rouse, filePath string, cfg *config.AppConfig) *exec.Cmd { @@ -17,85 +14,11 @@ func handleRDP(r *Rouse, filePath string, cfg *config.AppConfig) *exec.Cmd { } func handleSSH(r *Rouse, currentPath string, cfg *config.AppConfig) *exec.Cmd { - clientPath := filepath.Join(currentPath, "client") - command := fmt.Sprintf("%s %s -P %s", clientPath, r.Command, r.Value) - cmd := awakenCommand(command) + cmd := awakenSSHCommand(r, currentPath, cfg) return cmd } -func structureMySQLCommand(command string) string { - command = strings.ReplaceAll(command, "mysql ", "") - db := &DBCommand{} - paramSlice := strings.Split(command, " ") - for i, v := range paramSlice { - if strings.HasPrefix(v, "-p") { - db.Password = paramSlice[i][2:] - continue - } - switch v { - case "-u": - db.User = paramSlice[i+1] - case "-h": - db.Host = paramSlice[i+1] - case "-P": - db.Port = paramSlice[i+1] - } - } - db.DBName = paramSlice[len(paramSlice)-1] - command = fmt.Sprintf( - "mysql -u %s -p%s -h %s -P %s %s", - db.User, db.Password, db.Host, db.Port, db.DBName, - ) - return command -} - -func structureRedisCommand(command string) string { - command = strings.ReplaceAll(command, "redis-cli ", "") - db := &DBCommand{} - paramSlice := strings.Split(command, " ") - for i, v := range paramSlice { - switch v { - case "-a": - db.Password = paramSlice[i+1] - case "-h": - db.Host = paramSlice[i+1] - case "-p": - db.Port = paramSlice[i+1] - } - } - cmd := fmt.Sprintf( - "redis-cli -h %s -p %s -a %s", - db.Host, db.Port, db.Password, - ) - return cmd -} - -func structurePostgreSQLCommand(command string) string { - command = strings.Trim(strings.ReplaceAll(command, "psql ", ""), `"`) - db := &DBCommand{} - for _, v := range strings.Split(command, " ") { - tp, val := strings.Split(v, "=")[0], strings.Split(v, "=")[1] - switch tp { - case "user": - db.User = val - case "password": - db.Password = val - case "host": - db.Host = val - case "port": - db.Port = val - case "dbname": - db.DBName = val - } - } - command = fmt.Sprintf( - "PGPASSWORD=%s psql -U %s -h %s -p %s -d %s", - db.Password, db.User, db.Host, db.Port, db.DBName, - ) - return command -} - -func handleDB(r *Rouse, command string, cfg *config.AppConfig) *exec.Cmd { - cmd := awakenCommand(command) +func handleDB(r *Rouse, cfg *config.AppConfig) *exec.Cmd { + cmd := awakenDBCommand(r, cfg) return cmd } diff --git a/go-client/pkg/awaken/awaken_windows.go b/go-client/pkg/awaken/awaken_windows.go index f28a106..8d5df0d 100755 --- a/go-client/pkg/awaken/awaken_windows.go +++ b/go-client/pkg/awaken/awaken_windows.go @@ -71,19 +71,7 @@ func handleSSH(r *Rouse, currentPath string, cfg *config.AppConfig) *exec.Cmd { return exec.Command(appPath, strings.Split(commands, " ")...) } -func structureMySQLCommand(command string) string { - return "" -} - -func structureRedisCommand(command string) string { - return "" -} - -func structurePostgreSQLCommand(command string) string { - return "" -} - -func handleDB(r *Rouse, command string, cfg *config.AppConfig) *exec.Cmd { +func handleDB(r *Rouse, cfg *config.AppConfig) *exec.Cmd { var appItem *config.AppItem appLst := cfg.Windows.Databases for _, app := range appLst { diff --git a/go-client/pkg/config/config.go b/go-client/pkg/config/config.go index 5f9a722..9ca2c9d 100644 --- a/go-client/pkg/config/config.go +++ b/go-client/pkg/config/config.go @@ -70,7 +70,8 @@ func GetConf() AppConfig { var GlobalConfig *AppConfig func getDefaultConfig() AppConfig { - filePath := filepath.Join(filepath.Dir(os.Args[0]), "config.json") + //filePath := filepath.Join(filepath.Dir(os.Args[0]), "config.json") + filePath := filepath.Join("/Users/halo/golang/clients/interface/bin/config.json") jsonFile, err := os.Open(filePath) if err != nil { global.LOG.Error(err.Error()) diff --git a/interface/.gitignore b/interface/.gitignore index c148942..a50bc28 100644 --- a/interface/.gitignore +++ b/interface/.gitignore @@ -23,4 +23,5 @@ pnpm-debug.log* *.sw? #Electron-builder output -/dist_electron \ No newline at end of file +/dist_electron +bin/* diff --git a/interface/bin/.gitkeep b/interface/bin/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/interface/package.json b/interface/package.json index e6b86f1..5b4f7f0 100644 --- a/interface/package.json +++ b/interface/package.json @@ -1,7 +1,8 @@ { "name": "interface", - "author": "Fit2Cloud Technology Co., Ltd.;", + "author": "Fit2Cloud Technology Co., Ltd.; ", "version": "v2.0.0", + "homepage": "https://jumpserver.org", "private": true, "scripts": { "serve": "vue-cli-service electron:serve", @@ -38,6 +39,11 @@ "sass-loader": "^13.3.2", "vue-cli-plugin-electron-builder": "~2.1.1" }, + "overrides": { + "vue-cli-plugin-electron-builder": { + "electron-builder": "^23.1.0" + } + }, "eslintConfig": { "root": true, "env": { diff --git a/interface/src/background.js b/interface/src/background.js index c010d8a..54306ec 100644 --- a/interface/src/background.js +++ b/interface/src/background.js @@ -3,6 +3,7 @@ import {createProtocol} from "vue-cli-plugin-electron-builder/lib"; import installExtension, {VUEJS3_DEVTOOLS} from "electron-devtools-installer"; import path from 'path' import fse from 'fs-extra' +import {execFile} from "child_process"; const isDevelopment = process.env.NODE_ENV !== "production"; // Scheme must be registered before the app is ready @@ -10,9 +11,11 @@ protocol.registerSchemesAsPrivileged([ {scheme: "app", privileges: {secure: true, standard: true}}, ]); +let mainWindow + async function createWindow() { // Create the browser window. - const win = new BrowserWindow({ + mainWindow = new BrowserWindow({ width: 860, height: 550, center: true, @@ -34,12 +37,13 @@ async function createWindow() { if (process.env.WEBPACK_DEV_SERVER_URL) { // Load the url of the dev server if in development mode - await win.loadURL(process.env.WEBPACK_DEV_SERVER_URL); - // if (!process.env.IS_TEST) win.webContents.openDevTools() + await mainWindow.loadURL(process.env.WEBPACK_DEV_SERVER_URL); + // if (!process.env.IS_TEST) mainWindow.webContents.openDevTools() } else { createProtocol("app"); // Load the index.html when not in development - win.loadURL("app://./index.html"); + await mainWindow.loadURL("app://./index.html"); + // mainWindow.webContents.openDevTools() } } @@ -105,8 +109,80 @@ if (isDevelopment) { } } -const STORE_PATH = app.getPath('appData') -const configFilePath = path.join(STORE_PATH, 'JumpServer', 'Client', 'config.json') + +if (process.defaultApp) { + if (process.argv.length >= 2) { + app.setAsDefaultProtocolClient('jms', process.execPath, [path.resolve(process.argv[1])]) + } +} else { + app.setAsDefaultProtocolClient('jms') +} + +const handleOpenFromUrl = (url) => { + let subPath + if (isDevelopment && !process.env.IS_TEST) { + subPath = "bin" + } else { + subPath = process.resourcesPath + "/bin" + } + if (process.platform === "linux") { + switch (process.arch) { + case 'x32': + case 'x64': + subPath += "/linux-amd64" + break; + case 'arm': + case 'arm64': + subPath += "/linux-arm64" + break; + } + } else if (process.platform === "darwin") { + subPath += "/darwin" + } + console.log(subPath) + let exeFilePath = path.join(subPath, 'JumpServerClient') + const {execFile} = require('child_process') + execFile(exeFilePath, [url], (error, stdout, stderr) => { + if (error) { + console.log(error); + } + }); +} + +app.on('open-url', (event, urlStr) => { + handleOpenFromUrl(urlStr); +}); + +// 隐藏主窗口 +const hideWindow = () => { + if (mainWindow && !mainWindow.isDestroyed()) { + mainWindow.hide() + } +} + +app.on('second-instance', (event, commandLine, workingDirectory) => { + let commands = commandLine.slice(); + // commandLine 是一个数组, 其中最后一个数组元素为我们唤醒的链接 + let urlStr = commands.pop(); + handleOpenFromUrl(urlStr) +}) + + +let STORE_PATH +let configFilePath +if (process.platform === "win32") { + STORE_PATH = app.getPath('appData') + configFilePath = path.join(STORE_PATH, 'JumpServer', 'Client', 'config.json') +} else { + let subPath + if (isDevelopment && !process.env.IS_TEST) { + subPath = "bin" + } else { + subPath = process.resourcesPath + "/bin" + } + configFilePath = path.join(subPath, 'config.json') +} + const callBackUrlName = 'config-reply-get'//消息发布-发布名称 //读取本地文件 ipcMain.on('config-get', function (event) { @@ -153,21 +229,21 @@ ipcMain.on('config-set', function (event, type, value) { break } lst.forEach(item => { - if (value.is_default){ + if (value.is_default) { item.is_default = false } - if (item.match_first.length > 0){ - item.match_first = item.match_first.filter(item=>!value.match_first.includes(item)) + if (item.match_first.length > 0) { + item.match_first = item.match_first.filter(item => !value.match_first.includes(item)) } - if(item.name === value.name) { + if (item.name === value.name) { item.path = value.path item.is_default = value.is_default - item.is_set= value.is_set - item.match_first= value.match_first + item.is_set = value.is_set + item.match_first = value.match_first } }) const config_str = JSON.stringify(config) - fse.writeFileSync(configFilePath, config_str,"utf8") + fse.writeFileSync(configFilePath, config_str, "utf8") event.sender.send(callBackUrlName, 200, config_str); } }) diff --git a/interface/src/renderer/assets/iterm.png b/interface/src/renderer/assets/iterm.png new file mode 100644 index 0000000..dc8d95d Binary files /dev/null and b/interface/src/renderer/assets/iterm.png differ diff --git a/interface/src/renderer/assets/remmina.png b/interface/src/renderer/assets/remmina.png new file mode 100644 index 0000000..bf91068 Binary files /dev/null and b/interface/src/renderer/assets/remmina.png differ diff --git a/interface/src/renderer/assets/terminal.png b/interface/src/renderer/assets/terminal.png new file mode 100644 index 0000000..605ff16 Binary files /dev/null and b/interface/src/renderer/assets/terminal.png differ diff --git a/interface/src/renderer/layouts/Main.vue b/interface/src/renderer/layouts/Main.vue index d5f8b69..6d0c0f3 100644 --- a/interface/src/renderer/layouts/Main.vue +++ b/interface/src/renderer/layouts/Main.vue @@ -35,7 +35,7 @@ - 数据库工具 + 数据库 @@ -50,7 +50,7 @@ class="main-wrapper" >
- +
@@ -69,7 +69,7 @@ export default { setup() { const defaultActive = ref('sshPage') let activeItems = ref() - const os = ref('') + const os = ref() const {proxy} = getCurrentInstance(); let key = computed(() => { diff --git a/interface/src/renderer/pages/Databases.vue b/interface/src/renderer/pages/Databases.vue index ecf5ff5..604dea8 100644 --- a/interface/src/renderer/pages/Databases.vue +++ b/interface/src/renderer/pages/Databases.vue @@ -14,7 +14,7 @@ - + @@ -65,6 +65,10 @@ export default { type: Array, default: () => [] }, + os: { + type: String, + default: '' + }, }, data() { return { @@ -93,8 +97,11 @@ export default { }, changeFile() { const exe = document.getElementById("select-exe"); - if (exe == null) return; - this.selectItem.path = exe.files[0].path; + if (this.os === 'darwin') { + this.selectItem.path = '/Applications/' + exe.files[0].name.replace('.zip', ''); + } else { + this.selectItem.path = exe.files[0].path; + } }, onCancelItem() { this.clearSelectItem() diff --git a/interface/src/renderer/pages/FileTransfer.vue b/interface/src/renderer/pages/FileTransfer.vue index a9b854e..f360c60 100644 --- a/interface/src/renderer/pages/FileTransfer.vue +++ b/interface/src/renderer/pages/FileTransfer.vue @@ -13,7 +13,7 @@ - + [] }, + os: { + type: String, + default: '' + }, }, data() { return { @@ -84,8 +88,11 @@ export default { }, changeFile() { const exe = document.getElementById("select-exe"); - if (exe == null) return; - this.selectItem.path = exe.files[0].path; + if (this.os === 'darwin') { + this.selectItem.path = '/Applications/' + exe.files[0].name.replace('.zip', ''); + } else { + this.selectItem.path = exe.files[0].path; + } }, onCancelItem() { this.clearSelectItem() diff --git a/interface/src/renderer/pages/RemoteDesktop.vue b/interface/src/renderer/pages/RemoteDesktop.vue index a093859..3e61792 100644 --- a/interface/src/renderer/pages/RemoteDesktop.vue +++ b/interface/src/renderer/pages/RemoteDesktop.vue @@ -13,7 +13,7 @@ - + [] }, + os: { + type: String, + default: '' + }, }, data() { return { @@ -84,8 +88,11 @@ export default { }, changeFile() { const exe = document.getElementById("select-exe"); - if (exe == null) return; - this.selectItem.path = exe.files[0].path; + if (this.os === 'darwin') { + this.selectItem.path = '/Applications/' + exe.files[0].name.replace('.zip', ''); + } else { + this.selectItem.path = exe.files[0].path; + } }, onCancelItem() { this.clearSelectItem() diff --git a/interface/src/renderer/pages/Terminal.vue b/interface/src/renderer/pages/Terminal.vue index 5ae8569..629c78d 100644 --- a/interface/src/renderer/pages/Terminal.vue +++ b/interface/src/renderer/pages/Terminal.vue @@ -13,7 +13,7 @@ - + [] }, + os: { + type: String, + default: '' + }, }, data() { return { @@ -84,7 +88,11 @@ export default { }, changeFile() { const exe = document.getElementById("select-exe"); - if (exe == null) return; + // if (this.os === 'darwin') { + // this.selectItem.path = '/Applications/' + exe.files[0].name.replace('.zip', ''); + // } else { + // this.selectItem.path = exe.files[0].path; + // } this.selectItem.path = exe.files[0].path; }, onCancelItem() { diff --git a/interface/vue.config.js b/interface/vue.config.js index 128111f..1b50f8f 100644 --- a/interface/vue.config.js +++ b/interface/vue.config.js @@ -15,11 +15,15 @@ module.exports = { }, pluginOptions: { electronBuilder: { - nodeIntegration:true, + nodeIntegration: true, customFileProtocol: './', builderOptions: { - productName: 'JumpServer Config Clients', + productName: 'JumpServer本地客户端工具', appId: 'com.jumpserver.client', + asar: false, + extraResources: [ + "bin/**" + ], dmg: { contents: [ { @@ -48,12 +52,16 @@ module.exports = { ] }], // eslint-disable-next-line no-template-curly-in-string - artifactName: 'JumpServer-Config-Clients-${version}-${arch}.dmg' + artifactName: 'JumpServer-Clients-Installer-${os}-${version}-${arch}.dmg', + protocols: { + name: "Jms", + schemes: ["jms"] + }, }, win: { icon: 'build/icons/icon.ico', // eslint-disable-next-line no-template-curly-in-string - artifactName: 'JumpServer-Config-Clients-${version}-${arch}.exe', + artifactName: 'JumpServer-Clients-Installer-${os}-${version}-${arch}.exe', target: [{ target: 'nsis', arch: [ @@ -67,7 +75,20 @@ module.exports = { allowToChangeInstallationDirectory: true, }, linux: { - icon: 'build/icons/' + icon: 'build/icons/', + // eslint-disable-next-line no-template-curly-in-string + artifactName: 'JumpServer-Clients-Installer-${os}-${version}-${arch}.deb', + protocols: { + name: "Jms", + schemes: ["jms"] + }, + target: [{ + target: 'deb', + arch: [ + 'x64', + 'arm64' + ] + }] }, }, chainWebpackMainProcess: (config) => {