🚧重构中🚧

This commit is contained in:
lijiahang
2024-02-01 19:22:50 +08:00
parent 0263231fdb
commit 663e8568a1
12 changed files with 117 additions and 96 deletions

View File

@@ -17,7 +17,7 @@ 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 { TerminalTabs } 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';
@@ -62,7 +62,8 @@ export default defineStore('terminal', {
} as TerminalShortcutSetting,
},
hosts: {} as AuthorizedHostQueryResponse,
tabManager: new TerminalTabManager(),
tabManager: new TerminalTabManager(TerminalTabs.NEW_CONNECTION),
routerTabManager: [new TerminalTabManager()],
sessionManager: new TerminalSessionManager()
}),
@@ -130,9 +131,11 @@ export default defineStore('terminal', {
},
// 打开终端
openTerminal(record: HostQueryResponse) {
openTerminal(record: HostQueryResponse, panelIndex: number = 0) {
// 添加到最近连接
this.hosts.latestHosts = [...new Set([record.id, ...this.hosts.latestHosts])];
// 切换到终端面板页面
this.tabManager.openTab(TerminalTabs.TERMINAL_PANEL);
// 获取 seq
const tabSeqArr = this.tabManager.items
.map(s => s.seq)
@@ -141,9 +144,9 @@ export default defineStore('terminal', {
const nextSeq = tabSeqArr.length
? Math.max(...tabSeqArr) + 1
: 1;
// FIXME
// 打开 tab
this.tabManager.openTab({
type: TerminalTabType.TERMINAL,
key: nextSessionId(10),
seq: nextSeq,
title: `(${nextSeq}) ${record.alias || record.name}`,
@@ -164,7 +167,8 @@ export default defineStore('terminal', {
// 获取当前终端会话
getCurrentTerminalSession(tips: boolean = true) {
const tab = this.tabManager.getCurrentTab();
if (!tab || tab.type !== TerminalTabType.TERMINAL) {
// FIXME
if (!tab || tab.type !== 'TERMINAL') {
if (tips) {
Message.warning('请切换到终端标签页');
}

View File

@@ -6,6 +6,7 @@ export interface TerminalState {
preference: TerminalPreference;
hosts: AuthorizedHostQueryResponse;
tabManager: ITerminalTabManager;
routerTabManager: Array<ITerminalTabManager>;
sessionManager: ITerminalSessionManager;
}

View File

@@ -1,5 +1,5 @@
<template>
<a-dropdown class="terminal-context-menu"
<a-dropdown class="host-space-context-menu"
:popup-max-height="false"
trigger="contextMenu"
position="bl"
@@ -43,44 +43,45 @@
</div>
</div>
<!-- 命令 -->
<span class="snippet-item-command">
{{ item.command }}
</span>
<span class="snippet-item-command"
@click="clickCommand">
{{ item.command }}
</span>
</div>
</div>
<!-- 右键菜单 -->
<template #content>
<!-- 复制 -->
<a-doption @click="copyCommand">
<div class="terminal-context-menu-icon">
<div class="host-space-context-menu-icon">
<icon-copy />
</div>
<div>复制</div>
</a-doption>
<!-- 粘贴 -->
<a-doption @click="paste">
<div class="terminal-context-menu-icon">
<div class="host-space-context-menu-icon">
<icon-paste />
</div>
<div>粘贴</div>
</a-doption>
<!-- 执行 -->
<a-doption @click="exec">
<div class="terminal-context-menu-icon">
<div class="host-space-context-menu-icon">
<icon-thunderbolt />
</div>
<div>执行</div>
</a-doption>
<!-- 修改 -->
<a-doption @click="openUpdateSnippet(item)">
<div class="terminal-context-menu-icon">
<div class="host-space-context-menu-icon">
<icon-edit />
</div>
<div>修改</div>
</a-doption>
<!-- 删除 -->
<a-doption @click="removeSnippet(item.id)">
<div class="terminal-context-menu-icon">
<div class="host-space-context-menu-icon">
<icon-delete />
</div>
<div>删除</div>
@@ -88,7 +89,7 @@
<!-- 展开 -->
<a-doption v-if="!item.expand"
@click="() => item.expand = true">
<div class="terminal-context-menu-icon">
<div class="host-space-context-menu-icon">
<icon-expand />
</div>
<div>展开</div>
@@ -96,7 +97,7 @@
<!-- 收起 -->
<a-doption v-else
@click="() => item.expand = false">
<div class="terminal-context-menu-icon">
<div class="host-space-context-menu-icon">
<icon-shrink />
</div>
<div>收起</div>
@@ -155,6 +156,17 @@
}, 50);
});
// 点击命令
const clickCommand = (e: PointerEvent) => {
if (props.item.expand) {
// 获取选中的文本
const selectedText = window.getSelection()?.toString();
if (selectedText) {
e.stopPropagation();
}
}
};
// 复制命令
const copyCommand = () => {
copy(props.item.command, false);

View File

@@ -32,27 +32,25 @@
import type { HostQueryResponse } from '@/api/asset/host';
import { onMounted, ref } from 'vue';
import { useTerminalStore } from '@/store';
import { InnerTabs, TerminalTabType } from '../../types/terminal.const';
import { get } from 'lodash';
import { TerminalTabs } from '../../types/terminal.const';
const totalCount = 7;
const { tabManager, hosts, openTerminal } = useTerminalStore();
const combinedHandlers = ref<Array<CombinedHandlerItem>>([{
title: InnerTabs.NEW_CONNECTION.title,
settingTab: InnerTabs.NEW_CONNECTION,
type: TerminalTabType.SETTING,
icon: InnerTabs.NEW_CONNECTION.icon
title: TerminalTabs.NEW_CONNECTION.title,
tab: TerminalTabs.NEW_CONNECTION,
icon: TerminalTabs.NEW_CONNECTION.icon
}]);
// 点击组合操作元素
const clickHandlerItem = (item: CombinedHandlerItem) => {
if (item.type === TerminalTabType.SETTING) {
// 打开内置 tab
tabManager.openTab(item.settingTab as TerminalTabItem);
} else {
if (item.host) {
// 打开终端
openTerminal(item.host as HostQueryResponse);
} else {
// 打开 tab
tabManager.openTab(item.tab as TerminalTabItem);
}
};
@@ -71,7 +69,6 @@
.map(s => {
return {
title: `${s.alias || s.name} (${s.address})`,
type: TerminalTabType.TERMINAL,
host: s,
icon: 'icon-desktop'
};
@@ -80,15 +77,13 @@
combinedHandlers.value.push(...combinedHosts);
// 不足显示的行数用设置补充
if (totalCount - 1 - combinedHosts.length > 0) {
const fillTabs = Object.keys(InnerTabs)
.filter(s => s !== 'NEW_CONNECTION')
.map(s => get(InnerTabs, s) as TerminalTabItem)
const fillTabs = Object.values(TerminalTabs)
.filter(s => s.key !== TerminalTabs.NEW_CONNECTION.key)
.slice(0, totalCount - 1 - combinedHosts.length)
.map(s => {
return {
title: s.title,
settingTab: s,
type: TerminalTabType.SETTING,
tab: s,
icon: s.icon as string
};
});

View File

@@ -19,7 +19,7 @@
<script lang="ts" setup>
import type { SidebarAction } from '../../types/terminal.type';
import { InnerTabs } from '../../types/terminal.const';
import { TerminalTabs } from '../../types/terminal.const';
import { useTerminalStore } from '@/store';
import IconActions from './icon-actions.vue';
@@ -28,33 +28,33 @@
// 顶部操作
const topActions: Array<SidebarAction> = [
{
icon: InnerTabs.NEW_CONNECTION.icon,
content: InnerTabs.NEW_CONNECTION.title,
click: () => tabManager.openTab(InnerTabs.NEW_CONNECTION)
icon: TerminalTabs.NEW_CONNECTION.icon,
content: TerminalTabs.NEW_CONNECTION.title,
click: () => tabManager.openTab(TerminalTabs.NEW_CONNECTION)
},
];
// 底部操作
const bottomActions: Array<SidebarAction> = [
{
icon: InnerTabs.SHORTCUT_SETTING.icon,
content: InnerTabs.SHORTCUT_SETTING.title,
click: () => tabManager.openTab(InnerTabs.SHORTCUT_SETTING)
icon: TerminalTabs.SHORTCUT_SETTING.icon,
content: TerminalTabs.SHORTCUT_SETTING.title,
click: () => tabManager.openTab(TerminalTabs.SHORTCUT_SETTING)
},
{
icon: InnerTabs.DISPLAY_SETTING.icon,
content: InnerTabs.DISPLAY_SETTING.title,
click: () => tabManager.openTab(InnerTabs.DISPLAY_SETTING)
icon: TerminalTabs.DISPLAY_SETTING.icon,
content: TerminalTabs.DISPLAY_SETTING.title,
click: () => tabManager.openTab(TerminalTabs.DISPLAY_SETTING)
},
{
icon: InnerTabs.THEME_SETTING.icon,
content: InnerTabs.THEME_SETTING.title,
click: () => tabManager.openTab(InnerTabs.THEME_SETTING)
icon: TerminalTabs.THEME_SETTING.icon,
content: TerminalTabs.THEME_SETTING.title,
click: () => tabManager.openTab(TerminalTabs.THEME_SETTING)
},
{
icon: InnerTabs.TERMINAL_SETTING.icon,
content: InnerTabs.TERMINAL_SETTING.title,
click: () => tabManager.openTab(InnerTabs.TERMINAL_SETTING)
icon: TerminalTabs.TERMINAL_SETTING.icon,
content: TerminalTabs.TERMINAL_SETTING.title,
click: () => tabManager.openTab(TerminalTabs.TERMINAL_SETTING)
},
];

View File

@@ -6,23 +6,18 @@
<a-tab-pane v-for="tab in tabManager.items"
:key="tab.key"
:title="tab.title">
<!-- 设置 -->
<template v-if="tab.type === TerminalTabType.SETTING">
<!-- 新建连接 -->
<new-connection-view v-if="tab.key === InnerTabs.NEW_CONNECTION.key" />
<!-- 快捷键设置 -->
<terminal-shortcut-setting v-else-if="tab.key === InnerTabs.SHORTCUT_SETTING.key" />
<!-- 显示设置 -->
<terminal-display-setting v-else-if="tab.key === InnerTabs.DISPLAY_SETTING.key" />
<!-- 主题设置 -->
<terminal-theme-setting v-else-if="tab.key === InnerTabs.THEME_SETTING.key" />
<!-- 终端设置 -->
<terminal-general-setting v-else-if="tab.key === InnerTabs.TERMINAL_SETTING.key" />
</template>
<!-- 终端 -->
<template v-else-if="tab.type === TerminalTabType.TERMINAL">
<terminal-view :tab="tab" />
</template>
<!-- 新建连接 -->
<new-connection-view v-if="tab.key === TerminalTabs.NEW_CONNECTION.key" />
<!-- 快捷键设置 -->
<terminal-shortcut-setting v-else-if="tab.key === TerminalTabs.SHORTCUT_SETTING.key" />
<!-- 显示设置 -->
<terminal-display-setting v-else-if="tab.key === TerminalTabs.DISPLAY_SETTING.key" />
<!-- 主题设置 -->
<terminal-theme-setting v-else-if="tab.key === TerminalTabs.THEME_SETTING.key" />
<!-- 终端设置 -->
<terminal-general-setting v-else-if="tab.key === TerminalTabs.TERMINAL_SETTING.key" />
<!-- 主机终端 -->
<terminal-panel-view v-else-if="tab.key === TerminalTabs.TERMINAL_PANEL.key" />
</a-tab-pane>
</a-tabs>
<!-- 承载页推荐 -->
@@ -37,7 +32,7 @@
</script>
<script lang="ts" setup>
import { TerminalTabType, InnerTabs, TerminalShortcutKeys } from '../../types/terminal.const';
import { TerminalTabs, TerminalShortcutKeys } from '../../types/terminal.const';
import { useTerminalStore } from '@/store';
import { onMounted, onUnmounted, watch } from 'vue';
import { addEventListen, removeEventListen } from '@/utils/event';
@@ -47,16 +42,17 @@
import TerminalThemeSetting from '../setting/theme/terminal-theme-setting.vue';
import TerminalGeneralSetting from '../setting/general/terminal-general-setting.vue';
import TerminalShortcutSetting from '../setting/shortcut/terminal-shortcut-setting.vue';
import TerminalView from '../xterm/terminal-view.vue';
import TerminalPanelView from '@/views/host/terminal/components/layout/terminal-panel-view.vue';
const { preference, tabManager, sessionManager } = useTerminalStore();
// fixme TerminalTabType.TERMINAL
// 监听 tab 修改
watch(() => tabManager.active, (active, before) => {
if (before) {
// 失焦已经切换的终端
const beforeTab = tabManager.items.find(s => s.key === before);
if (beforeTab && beforeTab?.type === TerminalTabType.TERMINAL) {
if (beforeTab && beforeTab?.type === 'TerminalTabType.TERMINAL') {
sessionManager.getSession(before)?.blur();
}
}
@@ -66,10 +62,11 @@
if (!activeTab) {
return;
}
console.log(activeTab.title);
// 修改标题
document.title = activeTab.title;
// 终端自动聚焦
if (activeTab?.type === TerminalTabType.TERMINAL) {
if (activeTab?.type === 'TerminalTabType.TERMINAL') {
sessionManager.getSession(active)?.focus();
}
} else {
@@ -82,7 +79,7 @@
const handlerKeyboard = (event: Event) => {
// 当前页面非 terminal 的时候再触发快捷键 (terminal 有内置逻辑)
if (tabManager.active
&& tabManager.items.find(s => s.key === tabManager.active)?.type === TerminalTabType.TERMINAL) {
&& tabManager.items.find(s => s.key === tabManager.active)?.type === 'TerminalTabType.TERMINAL') {
return;
}
const e = event as KeyboardEvent;
@@ -114,7 +111,7 @@
break;
case TerminalShortcutKeys.OPEN_NEW_CONNECT_TAB:
// 切换到新建连接 tab
tabManager.openTab(InnerTabs.NEW_CONNECTION);
tabManager.openTab(TerminalTabs.NEW_CONNECTION);
break;
default:
break;

View File

@@ -0,0 +1,17 @@
<template>
</template>
<script lang="ts">
export default {
name: 'terminalPanelView'
};
</script>
<script lang="ts" setup>
</script>
<style lang="less" scoped>
</style>

View File

@@ -4,7 +4,7 @@ import type { Terminal } from 'xterm';
import useCopy from '@/hooks/copy';
import html2canvas from 'html2canvas';
import { useTerminalStore, useUserStore } from '@/store';
import { InnerTabs } from '../types/terminal.const';
import { TerminalTabs } from '../types/terminal.const';
import { saveAs } from 'file-saver';
import { Message } from '@arco-design/web-vue';
import { dateFormat } from '@/utils';
@@ -328,7 +328,7 @@ export default class TerminalSessionHandler implements ITerminalSessionHandler {
// 打开新建连接 tab
openNewConnectTab() {
this.tabManager.openTab(InnerTabs.NEW_CONNECTION);
this.tabManager.openTab(TerminalTabs.NEW_CONNECTION);
}
}

View File

@@ -1,5 +1,4 @@
import type { ITerminalTabManager, TerminalTabItem } from '../types/terminal.type';
import { InnerTabs } from '../types/terminal.const';
// 终端 tab 管理器实现
export default class TerminalTabManager implements ITerminalTabManager {
@@ -8,9 +7,14 @@ export default class TerminalTabManager implements ITerminalTabManager {
public items: Array<TerminalTabItem>;
constructor() {
this.active = InnerTabs.NEW_CONNECTION.key;
this.items = [InnerTabs.NEW_CONNECTION];
constructor(def: TerminalTabItem | undefined = undefined) {
if (def) {
this.active = def.key;
this.items = [def];
} else {
this.active = undefined as unknown as string;
this.items = [];
}
}
// 获取当前 tab

View File

@@ -33,7 +33,7 @@
<script lang="ts" setup>
import { ref, onBeforeMount, onUnmounted, onMounted } from 'vue';
import { dictKeys, InnerTabs } from './types/terminal.const';
import { dictKeys, TerminalTabs } from './types/terminal.const';
import { useCacheStore, useDictStore, useTerminalStore } from '@/store';
import useLoading from '@/hooks/loading';
import LayoutHeader from './components/layout/layout-header.vue';
@@ -85,7 +85,7 @@
// 事件处理
onMounted(() => {
// 默认标题
document.title = InnerTabs.NEW_CONNECTION.title;
document.title = TerminalTabs.NEW_CONNECTION.title;
// 注册关闭视口事件
// FIXME 开发阶段
// window.addEventListener('beforeunload', handleBeforeUnload);

View File

@@ -1,43 +1,36 @@
// tab 类型
import { ShortcutKeyItem } from './terminal.type';
// tab 类型
export const TerminalTabType = {
SETTING: 'setting',
TERMINAL: 'terminal',
};
// 内置 tab
export const InnerTabs = {
// 终端 tab
export const TerminalTabs = {
NEW_CONNECTION: {
key: 'newConnection',
title: '新建连接',
icon: 'icon-plus',
type: TerminalTabType.SETTING
},
SHORTCUT_SETTING: {
key: 'shortcutSetting',
title: '快捷键设置',
icon: 'icon-command',
type: TerminalTabType.SETTING
},
DISPLAY_SETTING: {
key: 'displaySetting',
title: '显示设置',
icon: 'icon-stamp',
type: TerminalTabType.SETTING
},
THEME_SETTING: {
key: 'themeSetting',
title: '主题设置',
icon: 'icon-palette',
type: TerminalTabType.SETTING
},
TERMINAL_SETTING: {
key: 'terminalSetting',
title: '终端设置',
icon: 'icon-settings',
type: TerminalTabType.SETTING
},
TERMINAL_PANEL: {
key: 'terminalPanel',
title: '主机终端',
icon: 'icon-desktop',
},
};

View File

@@ -12,7 +12,6 @@ import type { HostQueryResponse } from '@/api/asset/host';
export interface TerminalTabItem {
key: string;
title: string;
type: string;
icon?: string;
[key: string]: unknown;
@@ -32,9 +31,8 @@ export interface SidebarAction {
// 组合操作元素
export interface CombinedHandlerItem {
icon: string,
type: string,
title: string;
settingTab?: TerminalTabItem;
tab?: TerminalTabItem;
host?: HostQueryResponse;
}