From 3abd273f886d2068d9cf8248c47216638a1e5a49 Mon Sep 17 00:00:00 2001 From: lijiahangmax Date: Thu, 1 Feb 2024 00:18:13 +0800 Subject: [PATCH] =?UTF-8?q?=E5=86=99=E7=9A=84=E4=B8=8D=E5=A5=BD=3F=20?= =?UTF-8?q?=E9=82=A3=E5=B0=B1=E6=8E=A8=E7=BF=BB=E9=87=8D=E6=9D=A5.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/assets/style/host-space-layout.less | 24 +- orion-ops-ui/src/store/index.ts | 2 + .../src/store/modules/host-space/index.ts | 179 +++++++++ .../src/store/modules/host-space/types.ts | 97 +++++ .../components/command-snippet-list-item.vue | 16 +- .../components/layout/empty-recommend.vue | 163 ++++++++ .../components/{ => layout}/icon-actions.vue | 8 +- .../components/{ => layout}/layout-header.vue | 6 +- .../space/components/layout/layout-main.vue | 166 ++++++++ .../space/components/layout/left-sidebar.vue | 70 ++++ .../components/layout/loading-skeleton.vue | 29 ++ .../space/components/layout/right-sidebar.vue | 83 ++++ .../new-connection/host-group-view.vue | 107 +++++ .../new-connection/host-list-view.vue | 376 ++++++++++++++++++ .../components/new-connection/hosts-view.vue | 139 +++++++ .../new-connection/new-connection-view.vue | 142 +++++++ .../components/setting/block-setting-item.vue | 71 ++++ .../components/setting/ssh-extra-modal.vue | 146 +++++++ .../setting/terminal-action-bar-block.vue | 119 ++++++ .../setting/terminal-display-block.vue | 195 +++++++++ .../setting/terminal-display-setting.vue | 31 ++ .../components/setting/terminal-example.vue | 59 +++ .../setting/terminal-general-setting.vue | 31 ++ .../setting/terminal-interact-block.vue | 112 ++++++ .../setting/terminal-plugins-block.vue | 67 ++++ .../setting/terminal-right-menu-block.vue | 234 +++++++++++ .../setting/terminal-session-block.vue | 69 ++++ .../terminal-shortcut-action-block.vue | 69 ++++ .../setting/terminal-shortcut-keys-block.vue | 157 ++++++++ .../setting/terminal-shortcut-setting.vue | 248 ++++++++++++ .../setting/terminal-theme-block.vue | 165 ++++++++ .../setting/terminal-theme-setting.vue | 25 ++ orion-ops-ui/src/views/host/space/index.vue | 30 +- .../src/views/host/space/types/const.ts | 247 ++++++++++++ .../src/views/host/space/types/type.ts | 55 +++ .../xterm/terminal-context-menu.vue | 4 +- .../components/xterm/terminal-view.vue | 2 +- .../host/terminal/types/terminal.const.ts | 6 +- 38 files changed, 3701 insertions(+), 48 deletions(-) create mode 100644 orion-ops-ui/src/store/modules/host-space/index.ts create mode 100644 orion-ops-ui/src/store/modules/host-space/types.ts create mode 100644 orion-ops-ui/src/views/host/space/components/layout/empty-recommend.vue rename orion-ops-ui/src/views/host/space/components/{ => layout}/icon-actions.vue (79%) rename orion-ops-ui/src/views/host/space/components/{ => layout}/layout-header.vue (96%) create mode 100644 orion-ops-ui/src/views/host/space/components/layout/layout-main.vue create mode 100644 orion-ops-ui/src/views/host/space/components/layout/left-sidebar.vue create mode 100644 orion-ops-ui/src/views/host/space/components/layout/loading-skeleton.vue create mode 100644 orion-ops-ui/src/views/host/space/components/layout/right-sidebar.vue create mode 100644 orion-ops-ui/src/views/host/space/components/new-connection/host-group-view.vue create mode 100644 orion-ops-ui/src/views/host/space/components/new-connection/host-list-view.vue create mode 100644 orion-ops-ui/src/views/host/space/components/new-connection/hosts-view.vue create mode 100644 orion-ops-ui/src/views/host/space/components/new-connection/new-connection-view.vue create mode 100644 orion-ops-ui/src/views/host/space/components/setting/block-setting-item.vue create mode 100644 orion-ops-ui/src/views/host/space/components/setting/ssh-extra-modal.vue create mode 100644 orion-ops-ui/src/views/host/space/components/setting/terminal-action-bar-block.vue create mode 100644 orion-ops-ui/src/views/host/space/components/setting/terminal-display-block.vue create mode 100644 orion-ops-ui/src/views/host/space/components/setting/terminal-display-setting.vue create mode 100644 orion-ops-ui/src/views/host/space/components/setting/terminal-example.vue create mode 100644 orion-ops-ui/src/views/host/space/components/setting/terminal-general-setting.vue create mode 100644 orion-ops-ui/src/views/host/space/components/setting/terminal-interact-block.vue create mode 100644 orion-ops-ui/src/views/host/space/components/setting/terminal-plugins-block.vue create mode 100644 orion-ops-ui/src/views/host/space/components/setting/terminal-right-menu-block.vue create mode 100644 orion-ops-ui/src/views/host/space/components/setting/terminal-session-block.vue create mode 100644 orion-ops-ui/src/views/host/space/components/setting/terminal-shortcut-action-block.vue create mode 100644 orion-ops-ui/src/views/host/space/components/setting/terminal-shortcut-keys-block.vue create mode 100644 orion-ops-ui/src/views/host/space/components/setting/terminal-shortcut-setting.vue create mode 100644 orion-ops-ui/src/views/host/space/components/setting/terminal-theme-block.vue create mode 100644 orion-ops-ui/src/views/host/space/components/setting/terminal-theme-setting.vue create mode 100644 orion-ops-ui/src/views/host/space/types/type.ts diff --git a/orion-ops-ui/src/assets/style/host-space-layout.less b/orion-ops-ui/src/assets/style/host-space-layout.less index 0e51a5a5..3dc648bd 100644 --- a/orion-ops-ui/src/assets/style/host-space-layout.less +++ b/orion-ops-ui/src/assets/style/host-space-layout.less @@ -191,14 +191,14 @@ body[host-space-theme='dark'] .arco-modal-container { } // 侧栏图标 -.terminal-sidebar-icon-wrapper { +.host-space-sidebar-icon-wrapper { width: var(--sidebar-icon-wrapper-size); height: var(--sidebar-icon-wrapper-size); display: flex; align-items: center; justify-content: center; - .terminal-sidebar-icon { + .host-space-sidebar-icon { width: var(--sidebar-icon-size); height: var(--sidebar-icon-size); font-size: var(--sidebar-icon-font-size); @@ -226,44 +226,44 @@ body[host-space-theme='dark'] .arco-modal-container { } // 终端设置容器 -.terminal-setting-container { +.host-space-setting-container { padding: 32px 16px 16px 16px; width: 100%; display: flex; flex-direction: column; - .terminal-setting-wrapper { + .host-space-setting-wrapper { min-width: 932px; max-width: 90%; margin: 0 auto; position: relative; } - .terminal-setting-title { + .host-space-setting-title { margin: 0 0 24px 0; user-select: none; font-size: 1.65em; color: var(--color-content-text-3); } - .terminal-setting-block { + .host-space-setting-block { color: var(--color-content-text-2); margin-bottom: 24px; } - .terminal-setting-subtitle-wrapper { + .host-space-setting-subtitle-wrapper { display: flex; justify-content: space-between; align-items: flex-start; } - .terminal-setting-subtitle { + .host-space-setting-subtitle { margin: 0 0 16px 0; user-select: none; color: var(--color-content-text-3); } - .terminal-setting-body { + .host-space-setting-body { display: flex; &.block-body { @@ -277,13 +277,13 @@ body[host-space-theme='dark'] .arco-modal-container { } // tooltip 内容 -.terminal-tooltip-content { +.host-space-tooltip-content { color: var(--color-sidebar-tooltip-text); background: var(--color-sidebar-tooltip-bg); } -// 终端右键菜单 -.terminal-context-menu { +// 右键菜单 +.host-space-context-menu { .arco-dropdown-option { padding: 0 6px; line-height: 32px; diff --git a/orion-ops-ui/src/store/index.ts b/orion-ops-ui/src/store/index.ts index 5d570f6f..2dfe3bec 100644 --- a/orion-ops-ui/src/store/index.ts +++ b/orion-ops-ui/src/store/index.ts @@ -6,6 +6,7 @@ import useTabBarStore from './modules/tab-bar'; import useCacheStore from './modules/cache'; import useTipsStore from './modules/tips'; import useDictStore from './modules/dict'; +import useHostSpaceStore from './modules/host-space'; import useTerminalStore from './modules/terminal'; const pinia = createPinia(); @@ -19,6 +20,7 @@ export { useTipsStore, useDictStore, useTerminalStore, + useHostSpaceStore, }; export default pinia; diff --git a/orion-ops-ui/src/store/modules/host-space/index.ts b/orion-ops-ui/src/store/modules/host-space/index.ts new file mode 100644 index 00000000..47cdda28 --- /dev/null +++ b/orion-ops-ui/src/store/modules/host-space/index.ts @@ -0,0 +1,179 @@ +import type { + TerminalActionBarSetting, + TerminalDisplaySetting, + TerminalInteractSetting, + TerminalPluginsSetting, + TerminalPreference, + TerminalSessionSetting, + TerminalShortcutSetting, + TerminalState +} from './types'; +import type { AuthorizedHostQueryResponse } from '@/api/asset/asset-authorized-data'; +import type { HostQueryResponse } from '@/api/asset/host'; +import type { TerminalTheme, TerminalThemeSchema } from '@/api/asset/host-terminal'; +import { getCurrentAuthorizedHost } from '@/api/asset/asset-authorized-data'; +import { getTerminalThemes } from '@/api/asset/host-terminal'; +import { defineStore } from 'pinia'; +import { getPreference, updatePreference } from '@/api/user/preference'; +import { nextSessionId } from '@/utils'; +import { Message } from '@arco-design/web-vue'; +import { TerminalTabType } from '@/views/host/terminal/types/terminal.const'; +import TerminalTabManager from '@/views/host/terminal/handler/terminal-tab-manager'; +import TerminalSessionManager from '@/views/host/terminal/handler/terminal-session-manager'; + +// 终端偏好项 +export const TerminalPreferenceItem = { + // 新建连接类型 + NEW_CONNECTION_TYPE: 'newConnectionType', + // 终端主题 + THEME: 'theme', + // 显示设置 + DISPLAY_SETTING: 'displaySetting', + // 操作栏设置 + ACTION_BAR_SETTING: 'actionBarSetting', + // 右键菜单设置 + RIGHT_MENU_SETTING: 'rightMenuSetting', + // 交互设置 + INTERACT_SETTING: 'interactSetting', + // 插件设置 + PLUGINS_SETTING: 'pluginsSetting', + // 会话设置 + SESSION_SETTING: 'sessionSetting', + // 快捷键设置 + SHORTCUT_SETTING: 'shortcutSetting', +}; + +export default defineStore('hostSpace', { + state: (): TerminalState => ({ + preference: { + newConnectionType: 'group', + theme: { + schema: {} as TerminalThemeSchema + } as TerminalTheme, + displaySetting: {} as TerminalDisplaySetting, + actionBarSetting: {} as TerminalActionBarSetting, + rightMenuSetting: [], + interactSetting: {} as TerminalInteractSetting, + pluginsSetting: {} as TerminalPluginsSetting, + sessionSetting: {} as TerminalSessionSetting, + shortcutSetting: { + enabled: false, + keys: [] + } as TerminalShortcutSetting, + }, + hosts: {} as AuthorizedHostQueryResponse, + tabManager: new TerminalTabManager(), + sessionManager: new TerminalSessionManager() + }), + + actions: { + // 加载终端偏好 + async fetchPreference() { + try { + // 加载偏好 + const { data } = await getPreference('TERMINAL'); + // theme 不存在则默认加载第一个 + if (!data.theme?.name) { + const { data: themes } = await getTerminalThemes(); + data.theme = themes[0]; + // 更新默认主题偏好 + await this.updateTerminalPreference(TerminalPreferenceItem.THEME, data.theme); + } + // 移除禁用的快捷键 + if (data.shortcutSetting?.enabled) { + data.shortcutSetting.keys = data.shortcutSetting.keys.filter(s => s.enabled); + } else { + data.shortcutSetting = { + enabled: false, + keys: [] + }; + } + // 选择赋值 (不能修改引用) + const keys = Object.keys(this.preference); + keys.forEach(key => { + const item = data[key as keyof TerminalPreference]; + if (item) { + this.preference[key as keyof TerminalPreference] = item as any; + } + }); + } catch (e) { + Message.error('配置加载失败'); + } + }, + + // 更新终端偏好 + async updateTerminalPreference(item: string, value: any, setLocal = false) { + if (setLocal) { + this.preference[item as keyof TerminalPreference] = value; + } + try { + // 修改配置 + await updatePreference({ + type: 'TERMINAL', + item, + value + }); + } catch (e) { + Message.error('同步失败'); + } + }, + + // 加载主机列表 + async loadHosts() { + if (this.hosts.hostList?.length) { + return; + } + const { data } = await getCurrentAuthorizedHost(); + Object.keys(data).forEach(k => { + this.hosts[k as keyof AuthorizedHostQueryResponse] = data[k as keyof AuthorizedHostQueryResponse] as any; + }); + }, + + // 打开终端 + openTerminal(record: HostQueryResponse) { + // 添加到最近连接 + this.hosts.latestHosts = [...new Set([record.id, ...this.hosts.latestHosts])]; + // 获取 seq + const tabSeqArr = this.tabManager.items + .map(s => s.seq) + .filter(Boolean) + .map(Number); + const nextSeq = tabSeqArr.length + ? Math.max(...tabSeqArr) + 1 + : 1; + // 打开 tab + this.tabManager.openTab({ + type: TerminalTabType.TERMINAL, + key: nextSessionId(10), + seq: nextSeq, + title: `(${nextSeq}) ${record.alias || record.name}`, + hostId: record.id, + address: record.address + }); + }, + + // 复制并且打开终端 + openCopyTerminal(hostId: number) { + const host = this.hosts.hostList + .find(s => s.id === hostId); + if (host) { + this.openTerminal(host); + } + }, + + // 获取当前终端会话 + getCurrentTerminalSession(tips: boolean = true) { + const tab = this.tabManager.getCurrentTab(); + if (!tab || tab.type !== TerminalTabType.TERMINAL) { + if (tips) { + Message.warning('请切换到终端标签页'); + } + return; + } + // 获取处理器并截图 + return this.sessionManager.getSession(tab.key); + }, + + }, + +}); diff --git a/orion-ops-ui/src/store/modules/host-space/types.ts b/orion-ops-ui/src/store/modules/host-space/types.ts new file mode 100644 index 00000000..99624442 --- /dev/null +++ b/orion-ops-ui/src/store/modules/host-space/types.ts @@ -0,0 +1,97 @@ +import type { ITerminalSessionManager, ITerminalTabManager } from '@/views/host/terminal/types/terminal.type'; +import type { AuthorizedHostQueryResponse } from '@/api/asset/asset-authorized-data'; +import type { TerminalTheme } from '@/api/asset/host-terminal'; + +export interface TerminalState { + preference: TerminalPreference; + hosts: AuthorizedHostQueryResponse; + tabManager: ITerminalTabManager; + sessionManager: ITerminalSessionManager; +} + +// 终端配置 +export interface TerminalPreference { + newConnectionType: string; + theme: TerminalTheme; + displaySetting: TerminalDisplaySetting; + actionBarSetting: TerminalActionBarSetting; + rightMenuSetting: Array, + interactSetting: TerminalInteractSetting; + pluginsSetting: TerminalPluginsSetting; + sessionSetting: TerminalSessionSetting; + shortcutSetting: TerminalShortcutSetting; +} + +// 显示设置 +export interface TerminalDisplaySetting { + fontFamily?: string; + fontSize?: number; + lineHeight?: number; + fontWeight?: string | number; + fontWeightBold?: string | number; + cursorStyle?: string; + cursorBlink?: boolean; +} + +// 操作栏设置 +export interface TerminalActionBarSetting { + commandInput?: boolean; + connectStatus?: boolean; + + [key: string]: unknown; +} + +// 交互设置 +export interface TerminalInteractSetting { + fastScrollModifier: boolean; + altClickMovesCursor: boolean; + rightClickSelectsWord: boolean; + selectionChangeCopy: boolean; + copyAutoTrim: boolean; + pasteAutoTrim: boolean; + rightClickPaste: boolean; + enableRightClickMenu: boolean; + enableBell: boolean; + wordSeparator: string; +} + +// 插件设置 +export interface TerminalPluginsSetting { + enableWeblinkPlugin: boolean; + enableWebglPlugin: boolean; + enableImagePlugin: boolean; +} + +// 会话设置 +export interface TerminalSessionSetting { + terminalEmulationType: string; + scrollBackLine: number; +} + +// 终端快捷键设置 +export interface TerminalShortcutSetting { + enabled: boolean; + keys: Array; +} + +// 终端快捷键 +export interface ShortcutKey { + ctrlKey: boolean; + shiftKey: boolean; + altKey: boolean; + code: string; +} + +// 终端快捷键 +export interface TerminalShortcutKey extends ShortcutKey { + item: string; + enabled: boolean; +} + +// 终端快捷键编辑 +export interface TerminalShortcutKeyEditable extends TerminalShortcutKey { + editable: boolean; + content: string; + type: number; + shortcutKey?: string; +} diff --git a/orion-ops-ui/src/views/host/command-snippet/components/command-snippet-list-item.vue b/orion-ops-ui/src/views/host/command-snippet/components/command-snippet-list-item.vue index 2751fe2f..e6fda2db 100644 --- a/orion-ops-ui/src/views/host/command-snippet/components/command-snippet-list-item.vue +++ b/orion-ops-ui/src/views/host/command-snippet/components/command-snippet-list-item.vue @@ -1,5 +1,5 @@