🚧 重构中 🚧
This commit is contained in:
@@ -17,7 +17,7 @@ import { defineStore } from 'pinia';
|
|||||||
import { getPreference, updatePreference } from '@/api/user/preference';
|
import { getPreference, updatePreference } from '@/api/user/preference';
|
||||||
import { nextSessionId } from '@/utils';
|
import { nextSessionId } from '@/utils';
|
||||||
import { Message } from '@arco-design/web-vue';
|
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 TerminalTabManager from '@/views/host/terminal/handler/terminal-tab-manager';
|
||||||
import TerminalSessionManager from '@/views/host/terminal/handler/terminal-session-manager';
|
import TerminalSessionManager from '@/views/host/terminal/handler/terminal-session-manager';
|
||||||
|
|
||||||
@@ -62,7 +62,8 @@ export default defineStore('terminal', {
|
|||||||
} as TerminalShortcutSetting,
|
} as TerminalShortcutSetting,
|
||||||
},
|
},
|
||||||
hosts: {} as AuthorizedHostQueryResponse,
|
hosts: {} as AuthorizedHostQueryResponse,
|
||||||
tabManager: new TerminalTabManager(),
|
tabManager: new TerminalTabManager(TerminalTabs.NEW_CONNECTION),
|
||||||
|
routerTabManager: [new TerminalTabManager()],
|
||||||
sessionManager: new TerminalSessionManager()
|
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.hosts.latestHosts = [...new Set([record.id, ...this.hosts.latestHosts])];
|
||||||
|
// 切换到终端面板页面
|
||||||
|
this.tabManager.openTab(TerminalTabs.TERMINAL_PANEL);
|
||||||
// 获取 seq
|
// 获取 seq
|
||||||
const tabSeqArr = this.tabManager.items
|
const tabSeqArr = this.tabManager.items
|
||||||
.map(s => s.seq)
|
.map(s => s.seq)
|
||||||
@@ -141,9 +144,9 @@ export default defineStore('terminal', {
|
|||||||
const nextSeq = tabSeqArr.length
|
const nextSeq = tabSeqArr.length
|
||||||
? Math.max(...tabSeqArr) + 1
|
? Math.max(...tabSeqArr) + 1
|
||||||
: 1;
|
: 1;
|
||||||
|
// FIXME
|
||||||
// 打开 tab
|
// 打开 tab
|
||||||
this.tabManager.openTab({
|
this.tabManager.openTab({
|
||||||
type: TerminalTabType.TERMINAL,
|
|
||||||
key: nextSessionId(10),
|
key: nextSessionId(10),
|
||||||
seq: nextSeq,
|
seq: nextSeq,
|
||||||
title: `(${nextSeq}) ${record.alias || record.name}`,
|
title: `(${nextSeq}) ${record.alias || record.name}`,
|
||||||
@@ -164,7 +167,8 @@ export default defineStore('terminal', {
|
|||||||
// 获取当前终端会话
|
// 获取当前终端会话
|
||||||
getCurrentTerminalSession(tips: boolean = true) {
|
getCurrentTerminalSession(tips: boolean = true) {
|
||||||
const tab = this.tabManager.getCurrentTab();
|
const tab = this.tabManager.getCurrentTab();
|
||||||
if (!tab || tab.type !== TerminalTabType.TERMINAL) {
|
// FIXME
|
||||||
|
if (!tab || tab.type !== 'TERMINAL') {
|
||||||
if (tips) {
|
if (tips) {
|
||||||
Message.warning('请切换到终端标签页');
|
Message.warning('请切换到终端标签页');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ export interface TerminalState {
|
|||||||
preference: TerminalPreference;
|
preference: TerminalPreference;
|
||||||
hosts: AuthorizedHostQueryResponse;
|
hosts: AuthorizedHostQueryResponse;
|
||||||
tabManager: ITerminalTabManager;
|
tabManager: ITerminalTabManager;
|
||||||
|
routerTabManager: Array<ITerminalTabManager>;
|
||||||
sessionManager: ITerminalSessionManager;
|
sessionManager: ITerminalSessionManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<a-dropdown class="terminal-context-menu"
|
<a-dropdown class="host-space-context-menu"
|
||||||
:popup-max-height="false"
|
:popup-max-height="false"
|
||||||
trigger="contextMenu"
|
trigger="contextMenu"
|
||||||
position="bl"
|
position="bl"
|
||||||
@@ -43,44 +43,45 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- 命令 -->
|
<!-- 命令 -->
|
||||||
<span class="snippet-item-command">
|
<span class="snippet-item-command"
|
||||||
{{ item.command }}
|
@click="clickCommand">
|
||||||
</span>
|
{{ item.command }}
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- 右键菜单 -->
|
<!-- 右键菜单 -->
|
||||||
<template #content>
|
<template #content>
|
||||||
<!-- 复制 -->
|
<!-- 复制 -->
|
||||||
<a-doption @click="copyCommand">
|
<a-doption @click="copyCommand">
|
||||||
<div class="terminal-context-menu-icon">
|
<div class="host-space-context-menu-icon">
|
||||||
<icon-copy />
|
<icon-copy />
|
||||||
</div>
|
</div>
|
||||||
<div>复制</div>
|
<div>复制</div>
|
||||||
</a-doption>
|
</a-doption>
|
||||||
<!-- 粘贴 -->
|
<!-- 粘贴 -->
|
||||||
<a-doption @click="paste">
|
<a-doption @click="paste">
|
||||||
<div class="terminal-context-menu-icon">
|
<div class="host-space-context-menu-icon">
|
||||||
<icon-paste />
|
<icon-paste />
|
||||||
</div>
|
</div>
|
||||||
<div>粘贴</div>
|
<div>粘贴</div>
|
||||||
</a-doption>
|
</a-doption>
|
||||||
<!-- 执行 -->
|
<!-- 执行 -->
|
||||||
<a-doption @click="exec">
|
<a-doption @click="exec">
|
||||||
<div class="terminal-context-menu-icon">
|
<div class="host-space-context-menu-icon">
|
||||||
<icon-thunderbolt />
|
<icon-thunderbolt />
|
||||||
</div>
|
</div>
|
||||||
<div>执行</div>
|
<div>执行</div>
|
||||||
</a-doption>
|
</a-doption>
|
||||||
<!-- 修改 -->
|
<!-- 修改 -->
|
||||||
<a-doption @click="openUpdateSnippet(item)">
|
<a-doption @click="openUpdateSnippet(item)">
|
||||||
<div class="terminal-context-menu-icon">
|
<div class="host-space-context-menu-icon">
|
||||||
<icon-edit />
|
<icon-edit />
|
||||||
</div>
|
</div>
|
||||||
<div>修改</div>
|
<div>修改</div>
|
||||||
</a-doption>
|
</a-doption>
|
||||||
<!-- 删除 -->
|
<!-- 删除 -->
|
||||||
<a-doption @click="removeSnippet(item.id)">
|
<a-doption @click="removeSnippet(item.id)">
|
||||||
<div class="terminal-context-menu-icon">
|
<div class="host-space-context-menu-icon">
|
||||||
<icon-delete />
|
<icon-delete />
|
||||||
</div>
|
</div>
|
||||||
<div>删除</div>
|
<div>删除</div>
|
||||||
@@ -88,7 +89,7 @@
|
|||||||
<!-- 展开 -->
|
<!-- 展开 -->
|
||||||
<a-doption v-if="!item.expand"
|
<a-doption v-if="!item.expand"
|
||||||
@click="() => item.expand = true">
|
@click="() => item.expand = true">
|
||||||
<div class="terminal-context-menu-icon">
|
<div class="host-space-context-menu-icon">
|
||||||
<icon-expand />
|
<icon-expand />
|
||||||
</div>
|
</div>
|
||||||
<div>展开</div>
|
<div>展开</div>
|
||||||
@@ -96,7 +97,7 @@
|
|||||||
<!-- 收起 -->
|
<!-- 收起 -->
|
||||||
<a-doption v-else
|
<a-doption v-else
|
||||||
@click="() => item.expand = false">
|
@click="() => item.expand = false">
|
||||||
<div class="terminal-context-menu-icon">
|
<div class="host-space-context-menu-icon">
|
||||||
<icon-shrink />
|
<icon-shrink />
|
||||||
</div>
|
</div>
|
||||||
<div>收起</div>
|
<div>收起</div>
|
||||||
@@ -155,6 +156,17 @@
|
|||||||
}, 50);
|
}, 50);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 点击命令
|
||||||
|
const clickCommand = (e: PointerEvent) => {
|
||||||
|
if (props.item.expand) {
|
||||||
|
// 获取选中的文本
|
||||||
|
const selectedText = window.getSelection()?.toString();
|
||||||
|
if (selectedText) {
|
||||||
|
e.stopPropagation();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// 复制命令
|
// 复制命令
|
||||||
const copyCommand = () => {
|
const copyCommand = () => {
|
||||||
copy(props.item.command, false);
|
copy(props.item.command, false);
|
||||||
|
|||||||
@@ -32,27 +32,25 @@
|
|||||||
import type { HostQueryResponse } from '@/api/asset/host';
|
import type { HostQueryResponse } from '@/api/asset/host';
|
||||||
import { onMounted, ref } from 'vue';
|
import { onMounted, ref } from 'vue';
|
||||||
import { useTerminalStore } from '@/store';
|
import { useTerminalStore } from '@/store';
|
||||||
import { InnerTabs, TerminalTabType } from '../../types/terminal.const';
|
import { TerminalTabs } from '../../types/terminal.const';
|
||||||
import { get } from 'lodash';
|
|
||||||
|
|
||||||
const totalCount = 7;
|
const totalCount = 7;
|
||||||
const { tabManager, hosts, openTerminal } = useTerminalStore();
|
const { tabManager, hosts, openTerminal } = useTerminalStore();
|
||||||
|
|
||||||
const combinedHandlers = ref<Array<CombinedHandlerItem>>([{
|
const combinedHandlers = ref<Array<CombinedHandlerItem>>([{
|
||||||
title: InnerTabs.NEW_CONNECTION.title,
|
title: TerminalTabs.NEW_CONNECTION.title,
|
||||||
settingTab: InnerTabs.NEW_CONNECTION,
|
tab: TerminalTabs.NEW_CONNECTION,
|
||||||
type: TerminalTabType.SETTING,
|
icon: TerminalTabs.NEW_CONNECTION.icon
|
||||||
icon: InnerTabs.NEW_CONNECTION.icon
|
|
||||||
}]);
|
}]);
|
||||||
|
|
||||||
// 点击组合操作元素
|
// 点击组合操作元素
|
||||||
const clickHandlerItem = (item: CombinedHandlerItem) => {
|
const clickHandlerItem = (item: CombinedHandlerItem) => {
|
||||||
if (item.type === TerminalTabType.SETTING) {
|
if (item.host) {
|
||||||
// 打开内置 tab
|
|
||||||
tabManager.openTab(item.settingTab as TerminalTabItem);
|
|
||||||
} else {
|
|
||||||
// 打开终端
|
// 打开终端
|
||||||
openTerminal(item.host as HostQueryResponse);
|
openTerminal(item.host as HostQueryResponse);
|
||||||
|
} else {
|
||||||
|
// 打开 tab
|
||||||
|
tabManager.openTab(item.tab as TerminalTabItem);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -71,7 +69,6 @@
|
|||||||
.map(s => {
|
.map(s => {
|
||||||
return {
|
return {
|
||||||
title: `${s.alias || s.name} (${s.address})`,
|
title: `${s.alias || s.name} (${s.address})`,
|
||||||
type: TerminalTabType.TERMINAL,
|
|
||||||
host: s,
|
host: s,
|
||||||
icon: 'icon-desktop'
|
icon: 'icon-desktop'
|
||||||
};
|
};
|
||||||
@@ -80,15 +77,13 @@
|
|||||||
combinedHandlers.value.push(...combinedHosts);
|
combinedHandlers.value.push(...combinedHosts);
|
||||||
// 不足显示的行数用设置补充
|
// 不足显示的行数用设置补充
|
||||||
if (totalCount - 1 - combinedHosts.length > 0) {
|
if (totalCount - 1 - combinedHosts.length > 0) {
|
||||||
const fillTabs = Object.keys(InnerTabs)
|
const fillTabs = Object.values(TerminalTabs)
|
||||||
.filter(s => s !== 'NEW_CONNECTION')
|
.filter(s => s.key !== TerminalTabs.NEW_CONNECTION.key)
|
||||||
.map(s => get(InnerTabs, s) as TerminalTabItem)
|
|
||||||
.slice(0, totalCount - 1 - combinedHosts.length)
|
.slice(0, totalCount - 1 - combinedHosts.length)
|
||||||
.map(s => {
|
.map(s => {
|
||||||
return {
|
return {
|
||||||
title: s.title,
|
title: s.title,
|
||||||
settingTab: s,
|
tab: s,
|
||||||
type: TerminalTabType.SETTING,
|
|
||||||
icon: s.icon as string
|
icon: s.icon as string
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import type { SidebarAction } from '../../types/terminal.type';
|
import type { SidebarAction } from '../../types/terminal.type';
|
||||||
import { InnerTabs } from '../../types/terminal.const';
|
import { TerminalTabs } from '../../types/terminal.const';
|
||||||
import { useTerminalStore } from '@/store';
|
import { useTerminalStore } from '@/store';
|
||||||
import IconActions from './icon-actions.vue';
|
import IconActions from './icon-actions.vue';
|
||||||
|
|
||||||
@@ -28,33 +28,33 @@
|
|||||||
// 顶部操作
|
// 顶部操作
|
||||||
const topActions: Array<SidebarAction> = [
|
const topActions: Array<SidebarAction> = [
|
||||||
{
|
{
|
||||||
icon: InnerTabs.NEW_CONNECTION.icon,
|
icon: TerminalTabs.NEW_CONNECTION.icon,
|
||||||
content: InnerTabs.NEW_CONNECTION.title,
|
content: TerminalTabs.NEW_CONNECTION.title,
|
||||||
click: () => tabManager.openTab(InnerTabs.NEW_CONNECTION)
|
click: () => tabManager.openTab(TerminalTabs.NEW_CONNECTION)
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
// 底部操作
|
// 底部操作
|
||||||
const bottomActions: Array<SidebarAction> = [
|
const bottomActions: Array<SidebarAction> = [
|
||||||
{
|
{
|
||||||
icon: InnerTabs.SHORTCUT_SETTING.icon,
|
icon: TerminalTabs.SHORTCUT_SETTING.icon,
|
||||||
content: InnerTabs.SHORTCUT_SETTING.title,
|
content: TerminalTabs.SHORTCUT_SETTING.title,
|
||||||
click: () => tabManager.openTab(InnerTabs.SHORTCUT_SETTING)
|
click: () => tabManager.openTab(TerminalTabs.SHORTCUT_SETTING)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: InnerTabs.DISPLAY_SETTING.icon,
|
icon: TerminalTabs.DISPLAY_SETTING.icon,
|
||||||
content: InnerTabs.DISPLAY_SETTING.title,
|
content: TerminalTabs.DISPLAY_SETTING.title,
|
||||||
click: () => tabManager.openTab(InnerTabs.DISPLAY_SETTING)
|
click: () => tabManager.openTab(TerminalTabs.DISPLAY_SETTING)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: InnerTabs.THEME_SETTING.icon,
|
icon: TerminalTabs.THEME_SETTING.icon,
|
||||||
content: InnerTabs.THEME_SETTING.title,
|
content: TerminalTabs.THEME_SETTING.title,
|
||||||
click: () => tabManager.openTab(InnerTabs.THEME_SETTING)
|
click: () => tabManager.openTab(TerminalTabs.THEME_SETTING)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: InnerTabs.TERMINAL_SETTING.icon,
|
icon: TerminalTabs.TERMINAL_SETTING.icon,
|
||||||
content: InnerTabs.TERMINAL_SETTING.title,
|
content: TerminalTabs.TERMINAL_SETTING.title,
|
||||||
click: () => tabManager.openTab(InnerTabs.TERMINAL_SETTING)
|
click: () => tabManager.openTab(TerminalTabs.TERMINAL_SETTING)
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@@ -6,23 +6,18 @@
|
|||||||
<a-tab-pane v-for="tab in tabManager.items"
|
<a-tab-pane v-for="tab in tabManager.items"
|
||||||
:key="tab.key"
|
:key="tab.key"
|
||||||
:title="tab.title">
|
:title="tab.title">
|
||||||
<!-- 设置 -->
|
<!-- 新建连接 -->
|
||||||
<template v-if="tab.type === TerminalTabType.SETTING">
|
<new-connection-view v-if="tab.key === TerminalTabs.NEW_CONNECTION.key" />
|
||||||
<!-- 新建连接 -->
|
<!-- 快捷键设置 -->
|
||||||
<new-connection-view v-if="tab.key === InnerTabs.NEW_CONNECTION.key" />
|
<terminal-shortcut-setting v-else-if="tab.key === TerminalTabs.SHORTCUT_SETTING.key" />
|
||||||
<!-- 快捷键设置 -->
|
<!-- 显示设置 -->
|
||||||
<terminal-shortcut-setting v-else-if="tab.key === InnerTabs.SHORTCUT_SETTING.key" />
|
<terminal-display-setting v-else-if="tab.key === TerminalTabs.DISPLAY_SETTING.key" />
|
||||||
<!-- 显示设置 -->
|
<!-- 主题设置 -->
|
||||||
<terminal-display-setting v-else-if="tab.key === InnerTabs.DISPLAY_SETTING.key" />
|
<terminal-theme-setting v-else-if="tab.key === TerminalTabs.THEME_SETTING.key" />
|
||||||
<!-- 主题设置 -->
|
<!-- 终端设置 -->
|
||||||
<terminal-theme-setting v-else-if="tab.key === InnerTabs.THEME_SETTING.key" />
|
<terminal-general-setting v-else-if="tab.key === TerminalTabs.TERMINAL_SETTING.key" />
|
||||||
<!-- 终端设置 -->
|
<!-- 主机终端 -->
|
||||||
<terminal-general-setting v-else-if="tab.key === InnerTabs.TERMINAL_SETTING.key" />
|
<terminal-panel-view v-else-if="tab.key === TerminalTabs.TERMINAL_PANEL.key" />
|
||||||
</template>
|
|
||||||
<!-- 终端 -->
|
|
||||||
<template v-else-if="tab.type === TerminalTabType.TERMINAL">
|
|
||||||
<terminal-view :tab="tab" />
|
|
||||||
</template>
|
|
||||||
</a-tab-pane>
|
</a-tab-pane>
|
||||||
</a-tabs>
|
</a-tabs>
|
||||||
<!-- 承载页推荐 -->
|
<!-- 承载页推荐 -->
|
||||||
@@ -37,7 +32,7 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { TerminalTabType, InnerTabs, TerminalShortcutKeys } from '../../types/terminal.const';
|
import { TerminalTabs, TerminalShortcutKeys } from '../../types/terminal.const';
|
||||||
import { useTerminalStore } from '@/store';
|
import { useTerminalStore } from '@/store';
|
||||||
import { onMounted, onUnmounted, watch } from 'vue';
|
import { onMounted, onUnmounted, watch } from 'vue';
|
||||||
import { addEventListen, removeEventListen } from '@/utils/event';
|
import { addEventListen, removeEventListen } from '@/utils/event';
|
||||||
@@ -47,16 +42,17 @@
|
|||||||
import TerminalThemeSetting from '../setting/theme/terminal-theme-setting.vue';
|
import TerminalThemeSetting from '../setting/theme/terminal-theme-setting.vue';
|
||||||
import TerminalGeneralSetting from '../setting/general/terminal-general-setting.vue';
|
import TerminalGeneralSetting from '../setting/general/terminal-general-setting.vue';
|
||||||
import TerminalShortcutSetting from '../setting/shortcut/terminal-shortcut-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();
|
const { preference, tabManager, sessionManager } = useTerminalStore();
|
||||||
|
|
||||||
|
// fixme TerminalTabType.TERMINAL
|
||||||
// 监听 tab 修改
|
// 监听 tab 修改
|
||||||
watch(() => tabManager.active, (active, before) => {
|
watch(() => tabManager.active, (active, before) => {
|
||||||
if (before) {
|
if (before) {
|
||||||
// 失焦已经切换的终端
|
// 失焦已经切换的终端
|
||||||
const beforeTab = tabManager.items.find(s => s.key === 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();
|
sessionManager.getSession(before)?.blur();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -66,10 +62,11 @@
|
|||||||
if (!activeTab) {
|
if (!activeTab) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
console.log(activeTab.title);
|
||||||
// 修改标题
|
// 修改标题
|
||||||
document.title = activeTab.title;
|
document.title = activeTab.title;
|
||||||
// 终端自动聚焦
|
// 终端自动聚焦
|
||||||
if (activeTab?.type === TerminalTabType.TERMINAL) {
|
if (activeTab?.type === 'TerminalTabType.TERMINAL') {
|
||||||
sessionManager.getSession(active)?.focus();
|
sessionManager.getSession(active)?.focus();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -82,7 +79,7 @@
|
|||||||
const handlerKeyboard = (event: Event) => {
|
const handlerKeyboard = (event: Event) => {
|
||||||
// 当前页面非 terminal 的时候再触发快捷键 (terminal 有内置逻辑)
|
// 当前页面非 terminal 的时候再触发快捷键 (terminal 有内置逻辑)
|
||||||
if (tabManager.active
|
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;
|
return;
|
||||||
}
|
}
|
||||||
const e = event as KeyboardEvent;
|
const e = event as KeyboardEvent;
|
||||||
@@ -114,7 +111,7 @@
|
|||||||
break;
|
break;
|
||||||
case TerminalShortcutKeys.OPEN_NEW_CONNECT_TAB:
|
case TerminalShortcutKeys.OPEN_NEW_CONNECT_TAB:
|
||||||
// 切换到新建连接 tab
|
// 切换到新建连接 tab
|
||||||
tabManager.openTab(InnerTabs.NEW_CONNECTION);
|
tabManager.openTab(TerminalTabs.NEW_CONNECTION);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
<template>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
export default {
|
||||||
|
name: 'terminalPanelView'
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
@@ -4,7 +4,7 @@ import type { Terminal } from 'xterm';
|
|||||||
import useCopy from '@/hooks/copy';
|
import useCopy from '@/hooks/copy';
|
||||||
import html2canvas from 'html2canvas';
|
import html2canvas from 'html2canvas';
|
||||||
import { useTerminalStore, useUserStore } from '@/store';
|
import { useTerminalStore, useUserStore } from '@/store';
|
||||||
import { InnerTabs } from '../types/terminal.const';
|
import { TerminalTabs } from '../types/terminal.const';
|
||||||
import { saveAs } from 'file-saver';
|
import { saveAs } from 'file-saver';
|
||||||
import { Message } from '@arco-design/web-vue';
|
import { Message } from '@arco-design/web-vue';
|
||||||
import { dateFormat } from '@/utils';
|
import { dateFormat } from '@/utils';
|
||||||
@@ -328,7 +328,7 @@ export default class TerminalSessionHandler implements ITerminalSessionHandler {
|
|||||||
|
|
||||||
// 打开新建连接 tab
|
// 打开新建连接 tab
|
||||||
openNewConnectTab() {
|
openNewConnectTab() {
|
||||||
this.tabManager.openTab(InnerTabs.NEW_CONNECTION);
|
this.tabManager.openTab(TerminalTabs.NEW_CONNECTION);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import type { ITerminalTabManager, TerminalTabItem } from '../types/terminal.type';
|
import type { ITerminalTabManager, TerminalTabItem } from '../types/terminal.type';
|
||||||
import { InnerTabs } from '../types/terminal.const';
|
|
||||||
|
|
||||||
// 终端 tab 管理器实现
|
// 终端 tab 管理器实现
|
||||||
export default class TerminalTabManager implements ITerminalTabManager {
|
export default class TerminalTabManager implements ITerminalTabManager {
|
||||||
@@ -8,9 +7,14 @@ export default class TerminalTabManager implements ITerminalTabManager {
|
|||||||
|
|
||||||
public items: Array<TerminalTabItem>;
|
public items: Array<TerminalTabItem>;
|
||||||
|
|
||||||
constructor() {
|
constructor(def: TerminalTabItem | undefined = undefined) {
|
||||||
this.active = InnerTabs.NEW_CONNECTION.key;
|
if (def) {
|
||||||
this.items = [InnerTabs.NEW_CONNECTION];
|
this.active = def.key;
|
||||||
|
this.items = [def];
|
||||||
|
} else {
|
||||||
|
this.active = undefined as unknown as string;
|
||||||
|
this.items = [];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取当前 tab
|
// 获取当前 tab
|
||||||
|
|||||||
@@ -33,7 +33,7 @@
|
|||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref, onBeforeMount, onUnmounted, onMounted } from 'vue';
|
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 { useCacheStore, useDictStore, useTerminalStore } from '@/store';
|
||||||
import useLoading from '@/hooks/loading';
|
import useLoading from '@/hooks/loading';
|
||||||
import LayoutHeader from './components/layout/layout-header.vue';
|
import LayoutHeader from './components/layout/layout-header.vue';
|
||||||
@@ -85,7 +85,7 @@
|
|||||||
// 事件处理
|
// 事件处理
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
// 默认标题
|
// 默认标题
|
||||||
document.title = InnerTabs.NEW_CONNECTION.title;
|
document.title = TerminalTabs.NEW_CONNECTION.title;
|
||||||
// 注册关闭视口事件
|
// 注册关闭视口事件
|
||||||
// FIXME 开发阶段
|
// FIXME 开发阶段
|
||||||
// window.addEventListener('beforeunload', handleBeforeUnload);
|
// window.addEventListener('beforeunload', handleBeforeUnload);
|
||||||
|
|||||||
@@ -1,43 +1,36 @@
|
|||||||
// tab 类型
|
|
||||||
import { ShortcutKeyItem } from './terminal.type';
|
import { ShortcutKeyItem } from './terminal.type';
|
||||||
|
|
||||||
// tab 类型
|
// 终端 tab
|
||||||
export const TerminalTabType = {
|
export const TerminalTabs = {
|
||||||
SETTING: 'setting',
|
|
||||||
TERMINAL: 'terminal',
|
|
||||||
};
|
|
||||||
|
|
||||||
// 内置 tab
|
|
||||||
export const InnerTabs = {
|
|
||||||
NEW_CONNECTION: {
|
NEW_CONNECTION: {
|
||||||
key: 'newConnection',
|
key: 'newConnection',
|
||||||
title: '新建连接',
|
title: '新建连接',
|
||||||
icon: 'icon-plus',
|
icon: 'icon-plus',
|
||||||
type: TerminalTabType.SETTING
|
|
||||||
},
|
},
|
||||||
SHORTCUT_SETTING: {
|
SHORTCUT_SETTING: {
|
||||||
key: 'shortcutSetting',
|
key: 'shortcutSetting',
|
||||||
title: '快捷键设置',
|
title: '快捷键设置',
|
||||||
icon: 'icon-command',
|
icon: 'icon-command',
|
||||||
type: TerminalTabType.SETTING
|
|
||||||
},
|
},
|
||||||
DISPLAY_SETTING: {
|
DISPLAY_SETTING: {
|
||||||
key: 'displaySetting',
|
key: 'displaySetting',
|
||||||
title: '显示设置',
|
title: '显示设置',
|
||||||
icon: 'icon-stamp',
|
icon: 'icon-stamp',
|
||||||
type: TerminalTabType.SETTING
|
|
||||||
},
|
},
|
||||||
THEME_SETTING: {
|
THEME_SETTING: {
|
||||||
key: 'themeSetting',
|
key: 'themeSetting',
|
||||||
title: '主题设置',
|
title: '主题设置',
|
||||||
icon: 'icon-palette',
|
icon: 'icon-palette',
|
||||||
type: TerminalTabType.SETTING
|
|
||||||
},
|
},
|
||||||
TERMINAL_SETTING: {
|
TERMINAL_SETTING: {
|
||||||
key: 'terminalSetting',
|
key: 'terminalSetting',
|
||||||
title: '终端设置',
|
title: '终端设置',
|
||||||
icon: 'icon-settings',
|
icon: 'icon-settings',
|
||||||
type: TerminalTabType.SETTING
|
},
|
||||||
|
TERMINAL_PANEL: {
|
||||||
|
key: 'terminalPanel',
|
||||||
|
title: '主机终端',
|
||||||
|
icon: 'icon-desktop',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ import type { HostQueryResponse } from '@/api/asset/host';
|
|||||||
export interface TerminalTabItem {
|
export interface TerminalTabItem {
|
||||||
key: string;
|
key: string;
|
||||||
title: string;
|
title: string;
|
||||||
type: string;
|
|
||||||
icon?: string;
|
icon?: string;
|
||||||
|
|
||||||
[key: string]: unknown;
|
[key: string]: unknown;
|
||||||
@@ -32,9 +31,8 @@ export interface SidebarAction {
|
|||||||
// 组合操作元素
|
// 组合操作元素
|
||||||
export interface CombinedHandlerItem {
|
export interface CombinedHandlerItem {
|
||||||
icon: string,
|
icon: string,
|
||||||
type: string,
|
|
||||||
title: string;
|
title: string;
|
||||||
settingTab?: TerminalTabItem;
|
tab?: TerminalTabItem;
|
||||||
host?: HostQueryResponse;
|
host?: HostQueryResponse;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user