♻️ 终端面板开发完成
This commit is contained in:
@@ -160,7 +160,7 @@ export default defineStore('terminal', {
|
|||||||
},
|
},
|
||||||
|
|
||||||
// 复制并且打开终端
|
// 复制并且打开终端
|
||||||
openCopyTerminal(hostId: number, panelIndex: number = 0) {
|
copyTerminalSession(hostId: number, panelIndex: number = 0) {
|
||||||
const host = this.hosts.hostList
|
const host = this.hosts.hostList
|
||||||
.find(s => s.id === hostId);
|
.find(s => s.id === hostId);
|
||||||
if (host) {
|
if (host) {
|
||||||
@@ -168,28 +168,35 @@ export default defineStore('terminal', {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// 获取当前终端会话
|
// 检查当前是否为终端页面 并且获取当前终端会话
|
||||||
getCurrentTerminalSession(tips: boolean = true) {
|
getAndCheckCurrentTerminalSession(tips: boolean = true) {
|
||||||
// 获取当前 tab
|
// 获取当前 activeTab
|
||||||
const tab = this.tabManager.getCurrentTab();
|
const activeTab = this.tabManager.active;
|
||||||
if (!tab || tab.key !== TerminalTabs.TERMINAL_PANEL.key) {
|
if (activeTab !== TerminalTabs.TERMINAL_PANEL.key) {
|
||||||
if (tips) {
|
if (tips) {
|
||||||
Message.warning('请切换到终端标签页');
|
Message.warning('请切换到终端标签页');
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// 获取当前会话
|
||||||
|
const session = this.getCurrentTerminalSession();
|
||||||
|
if (!session && tips) {
|
||||||
|
Message.warning('请打开终端');
|
||||||
|
}
|
||||||
|
return session;
|
||||||
|
},
|
||||||
|
|
||||||
|
// 获取当前终端会话
|
||||||
|
getCurrentTerminalSession() {
|
||||||
// 获取面板会话
|
// 获取面板会话
|
||||||
const activeTab = this.panelManager
|
const panelTab = this.panelManager
|
||||||
.getCurrentPanel()
|
.getCurrentPanel()
|
||||||
.getCurrentTab();
|
.getCurrentTab();
|
||||||
if (!activeTab || activeTab.type !== TerminalPanelTabType.TERMINAL) {
|
if (!panelTab || panelTab.type !== TerminalPanelTabType.TERMINAL) {
|
||||||
if (tips) {
|
|
||||||
Message.warning('请打开终端');
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// 获取会话
|
// 获取会话
|
||||||
return this.sessionManager.getSession(activeTab.key);
|
return this.sessionManager.getSession(panelTab.key);
|
||||||
},
|
},
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -267,7 +267,7 @@
|
|||||||
// 关闭回调
|
// 关闭回调
|
||||||
const onClose = () => {
|
const onClose = () => {
|
||||||
// 聚焦终端
|
// 聚焦终端
|
||||||
getCurrentTerminalSession(false)?.focus();
|
getCurrentTerminalSession()?.focus();
|
||||||
};
|
};
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -125,7 +125,7 @@
|
|||||||
}>();
|
}>();
|
||||||
|
|
||||||
const { copy } = useCopy();
|
const { copy } = useCopy();
|
||||||
const { getCurrentTerminalSession } = useTerminalStore();
|
const { getAndCheckCurrentTerminalSession } = useTerminalStore();
|
||||||
|
|
||||||
let clickCount = 0;
|
let clickCount = 0;
|
||||||
|
|
||||||
@@ -184,7 +184,7 @@
|
|||||||
|
|
||||||
// 写入命令
|
// 写入命令
|
||||||
const write = (command: string) => {
|
const write = (command: string) => {
|
||||||
const handler = getCurrentTerminalSession()?.handler;
|
const handler = getAndCheckCurrentTerminalSession()?.handler;
|
||||||
if (handler && handler.enabledStatus('checkAppendMissing')) {
|
if (handler && handler.enabledStatus('checkAppendMissing')) {
|
||||||
handler.checkAppendMissing(command);
|
handler.checkAppendMissing(command);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,43 +45,26 @@
|
|||||||
import TerminalShortcutSetting from '../setting/shortcut/terminal-shortcut-setting.vue';
|
import TerminalShortcutSetting from '../setting/shortcut/terminal-shortcut-setting.vue';
|
||||||
import TerminalPanelsView from '@/views/host/terminal/components/layout/terminal-panels-view.vue';
|
import TerminalPanelsView from '@/views/host/terminal/components/layout/terminal-panels-view.vue';
|
||||||
|
|
||||||
const { preference, tabManager, sessionManager } = useTerminalStore();
|
const { preference, tabManager, getCurrentTerminalSession } = useTerminalStore();
|
||||||
|
|
||||||
// fixme title逻辑 失焦逻辑
|
// 监听 tab 切换
|
||||||
// 监听 tab 修改
|
|
||||||
watch(() => tabManager.active, (active, before) => {
|
watch(() => tabManager.active, (active, before) => {
|
||||||
if (before) {
|
// 失焦 tab
|
||||||
// 失焦已经切换的终端
|
if (before === TerminalTabs.TERMINAL_PANEL.key) {
|
||||||
const beforeTab = tabManager.items.find(s => s.key === before);
|
getCurrentTerminalSession()?.blur();
|
||||||
if (beforeTab && beforeTab?.type === 'TerminalTabType.TERMINAL') {
|
|
||||||
sessionManager.getSession(before)?.blur();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (active) {
|
// 聚焦 tab
|
||||||
// 获取 activeTab
|
if (active === TerminalTabs.TERMINAL_PANEL.key) {
|
||||||
const activeTab = tabManager.getCurrentTab();
|
getCurrentTerminalSession()?.focus();
|
||||||
if (!activeTab) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// 修改标题
|
|
||||||
document.title = activeTab.title;
|
|
||||||
// 终端自动聚焦
|
|
||||||
if (activeTab?.type === 'TerminalTabType.TERMINAL') {
|
|
||||||
sessionManager.getSession(active)?.focus();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// 修改标题
|
|
||||||
document.title = TerminalTabs.TERMINAL_PANEL.title;
|
|
||||||
}
|
}
|
||||||
|
// 修改标题
|
||||||
|
document.title = Object.values(TerminalTabs)
|
||||||
|
.find(s => s.key === active)?.title
|
||||||
|
|| TerminalTabs.TERMINAL_PANEL.title;
|
||||||
});
|
});
|
||||||
|
|
||||||
// 处理快捷键逻辑
|
// 处理全局快捷键逻辑
|
||||||
const handlerKeyboard = (event: Event) => {
|
const handlerKeyboard = (event: Event) => {
|
||||||
// 当前页面非 terminal 的时候再触发快捷键 (terminal 有内置逻辑)
|
|
||||||
// fixme panel 无数据继续触发
|
|
||||||
if (tabManager.getCurrentTab()?.key === TerminalTabs.TERMINAL_PANEL.key) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const e = event as KeyboardEvent;
|
const e = event as KeyboardEvent;
|
||||||
// 检测触发的快捷键
|
// 检测触发的快捷键
|
||||||
const key = preference.shortcutSetting.keys.find(key => {
|
const key = preference.shortcutSetting.keys.find(key => {
|
||||||
|
|||||||
@@ -28,7 +28,7 @@
|
|||||||
|
|
||||||
const emits = defineEmits(['openSftp', 'openTransfer']);
|
const emits = defineEmits(['openSftp', 'openTransfer']);
|
||||||
|
|
||||||
const { getCurrentTerminalSession } = useTerminalStore();
|
const { getAndCheckCurrentTerminalSession } = useTerminalStore();
|
||||||
|
|
||||||
const snippetRef = ref();
|
const snippetRef = ref();
|
||||||
|
|
||||||
@@ -65,7 +65,7 @@
|
|||||||
|
|
||||||
// 终端截屏
|
// 终端截屏
|
||||||
const screenshot = () => {
|
const screenshot = () => {
|
||||||
const handler = getCurrentTerminalSession()?.handler;
|
const handler = getAndCheckCurrentTerminalSession()?.handler;
|
||||||
if (handler && handler.enabledStatus('screenshot')) {
|
if (handler && handler.enabledStatus('screenshot')) {
|
||||||
handler.screenshot();
|
handler.screenshot();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,19 +10,23 @@
|
|||||||
@delete="k => panel.deleteTab(k as string)">
|
@delete="k => panel.deleteTab(k as string)">
|
||||||
<!-- 右侧按钮 -->
|
<!-- 右侧按钮 -->
|
||||||
<template #extra>
|
<template #extra>
|
||||||
<a-button>Action</a-button>
|
<a-space class="panel-extra">
|
||||||
|
<span class="extra-icon" @click="close">
|
||||||
|
<icon-close />
|
||||||
|
</span>
|
||||||
|
</a-space>
|
||||||
</template>
|
</template>
|
||||||
<!-- 终端面板 -->
|
<!-- 终端面板 -->
|
||||||
<a-tab-pane v-for="tab in panel.items"
|
<a-tab-pane v-for="tab in panel.items"
|
||||||
:key="tab.key">
|
:key="tab.key">
|
||||||
<!-- 标题 -->
|
<!-- 标题 -->
|
||||||
<template #title>
|
<template #title>
|
||||||
<span class="tab-title-wrapper">
|
<span class="tab-title-wrapper">
|
||||||
<span class="tab-title-icon">
|
<span class="tab-title-icon">
|
||||||
<component :is="tab.icon" />
|
<component :is="tab.icon" />
|
||||||
</span>
|
|
||||||
{{ tab.title }}
|
|
||||||
</span>
|
</span>
|
||||||
|
{{ tab.title }}
|
||||||
|
</span>
|
||||||
</template>
|
</template>
|
||||||
<!-- 终端 -->
|
<!-- 终端 -->
|
||||||
<terminal-view :tab="tab" />
|
<terminal-view :tab="tab" />
|
||||||
@@ -41,28 +45,55 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import type { ITerminalTabManager } from '../../types/terminal.type';
|
import type { ITerminalTabManager, TerminalPanelTabItem } from '../../types/terminal.type';
|
||||||
|
import { ref, watch } from 'vue';
|
||||||
|
import { useTerminalStore } from '@/store';
|
||||||
|
import { TerminalPanelTabType } from '../../types/terminal.const';
|
||||||
import TerminalView from '../xterm/terminal-view.vue';
|
import TerminalView from '../xterm/terminal-view.vue';
|
||||||
import HostListModal from '../new-connection/host-list-modal.vue';
|
import HostListModal from '../new-connection/host-list-modal.vue';
|
||||||
import { onMounted, ref } from 'vue';
|
|
||||||
import { useTerminalStore } from '@/store';
|
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
index: number,
|
index: number,
|
||||||
panel: ITerminalTabManager,
|
panel: ITerminalTabManager<TerminalPanelTabItem>,
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const { openTerminal } = useTerminalStore();
|
const emits = defineEmits(['close']);
|
||||||
|
|
||||||
|
const { sessionManager, openTerminal } = useTerminalStore();
|
||||||
|
|
||||||
const hostModal = ref();
|
const hostModal = ref();
|
||||||
|
|
||||||
|
// 监听 tab 切换
|
||||||
|
watch(() => props.panel.active, (active, before) => {
|
||||||
|
// 失焦自动终端
|
||||||
|
if (before) {
|
||||||
|
const beforeTab = props.panel.items.find(s => s.key === before);
|
||||||
|
if (beforeTab && beforeTab?.type === TerminalPanelTabType.TERMINAL) {
|
||||||
|
sessionManager.getSession(before)?.blur();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 终端自动聚焦
|
||||||
|
if (active) {
|
||||||
|
const activeTab = props.panel.items.find(s => s.key === active);
|
||||||
|
if (activeTab && activeTab?.type === TerminalPanelTabType.TERMINAL) {
|
||||||
|
sessionManager.getSession(active)?.focus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 无终端自动关闭
|
||||||
|
if (!props.panel.items.length) {
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// 打开主机模态框
|
// 打开主机模态框
|
||||||
const openHostModal = () => {
|
const openHostModal = () => {
|
||||||
hostModal.value.open();
|
hostModal.value.open();
|
||||||
};
|
};
|
||||||
|
|
||||||
// FIXME 全部关闭展示新增
|
// 关闭面板
|
||||||
onMounted(openHostModal);
|
const close = () => {
|
||||||
|
emits('close', props.index);
|
||||||
|
};
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -82,6 +113,27 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.panel-extra {
|
||||||
|
margin-right: 8px;
|
||||||
|
|
||||||
|
.extra-icon {
|
||||||
|
color: var(--color-panel-text-2);
|
||||||
|
transition: 0.2s;
|
||||||
|
font-size: 16px;
|
||||||
|
cursor: pointer;
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
border-radius: 50%;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: var(--color-bg-panel-icon-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
:deep(.arco-tabs) {
|
:deep(.arco-tabs) {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
@@ -129,7 +181,6 @@
|
|||||||
background: var(--color-bg-panel-icon-1);
|
background: var(--color-bg-panel-icon-1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.arco-tabs-nav-type-line .arco-tabs-tab:hover .arco-tabs-tab-title::before) {
|
:deep(.arco-tabs-nav-type-line .arco-tabs-tab:hover .arco-tabs-tab-title::before) {
|
||||||
@@ -214,7 +265,6 @@
|
|||||||
&:hover::after {
|
&:hover::after {
|
||||||
background: linear-gradient(270deg, var(--color-panel-gradient-start) 45%, var(--color-panel-gradient-end) 120%);
|
background: linear-gradient(270deg, var(--color-panel-gradient-start) 45%, var(--color-panel-gradient-end) 120%);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="terminal-panels-container">
|
<div class="terminal-panels-container">
|
||||||
<!-- 面板 -->
|
<!-- 面板 -->
|
||||||
<terminal-panel v-for="panelIndex in panelManager.panels.length"
|
<terminal-panel v-for="(panel, index) in panelManager.panels"
|
||||||
:key="panelIndex"
|
:key="index"
|
||||||
:index="panelIndex - 1"
|
:index="index"
|
||||||
:panel="panelManager.panels[panelIndex - 1]" />
|
:panel="panel"
|
||||||
|
@close="closePanel" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -16,11 +17,23 @@
|
|||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { useTerminalStore } from '@/store';
|
import { useTerminalStore } from '@/store';
|
||||||
import TerminalPanel from './terminal-panel.vue';
|
|
||||||
import { onUnmounted } from 'vue';
|
import { onUnmounted } from 'vue';
|
||||||
|
import { TerminalTabs } from '../../types/terminal.const';
|
||||||
|
import TerminalPanel from './terminal-panel.vue';
|
||||||
|
|
||||||
const { panelManager } = useTerminalStore();
|
const { tabManager, panelManager } = useTerminalStore();
|
||||||
// FIXME 全部关闭则关闭
|
|
||||||
|
// 移除面板
|
||||||
|
const closePanel = (index: number) => {
|
||||||
|
panelManager.getPanel(index)?.clear();
|
||||||
|
if (panelManager.panels.length == 1) {
|
||||||
|
// 关闭 tab
|
||||||
|
tabManager.deleteTab(TerminalTabs.TERMINAL_PANEL.key);
|
||||||
|
} else {
|
||||||
|
// 关闭面板
|
||||||
|
panelManager.removePanel(index);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// 卸载清空
|
// 卸载清空
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
@@ -34,5 +47,6 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
height: calc(100vh - var(--header-height));
|
height: calc(100vh - var(--header-height));
|
||||||
position: relative;
|
position: relative;
|
||||||
|
display: flex;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -19,9 +19,9 @@
|
|||||||
<terminal-shortcut-action-block v-model:enabled="enabled"
|
<terminal-shortcut-action-block v-model:enabled="enabled"
|
||||||
@reset="loadDefaultPreference"
|
@reset="loadDefaultPreference"
|
||||||
@save="savePreference" />
|
@save="savePreference" />
|
||||||
<!-- 系统快捷键 -->
|
<!-- 全局快捷键 -->
|
||||||
<terminal-shortcut-keys-block title="系统快捷键"
|
<terminal-shortcut-keys-block title="全局快捷键"
|
||||||
:type="TerminalShortcutType.TAB"
|
:type="TerminalShortcutType.GLOBAL"
|
||||||
:items="shortcutKeys"
|
:items="shortcutKeys"
|
||||||
@set-editable="setEditableStatus"
|
@set-editable="setEditableStatus"
|
||||||
@clear-editable="clearEditableStatus"
|
@clear-editable="clearEditableStatus"
|
||||||
|
|||||||
@@ -29,6 +29,12 @@ export default class TerminalPanelManager<T extends TerminalPanelTabItem = Termi
|
|||||||
return this.panels[index];
|
return this.panels[index];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 移除面板
|
||||||
|
removePanel(index: number) {
|
||||||
|
this.panels.splice(index, 1);
|
||||||
|
this.active = index >= this.panels.length ? this.panels.length - 1 : index;
|
||||||
|
};
|
||||||
|
|
||||||
// 重置
|
// 重置
|
||||||
reset() {
|
reset() {
|
||||||
for (let panel of this.panels) {
|
for (let panel of this.panels) {
|
||||||
|
|||||||
@@ -1,17 +1,22 @@
|
|||||||
import type { ShortcutKey, TerminalInteractSetting, TerminalShortcutKey } from '@/store/modules/terminal/types';
|
import type { ShortcutKey, TerminalInteractSetting, TerminalShortcutKey } from '@/store/modules/terminal/types';
|
||||||
import type { ITerminalSession, ITerminalSessionHandler, ITerminalTabManager, TerminalDomRef } from '../types/terminal.type';
|
import type { ITerminalSession, ITerminalSessionHandler, TerminalDomRef } from '../types/terminal.type';
|
||||||
import type { Terminal } from 'xterm';
|
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 { TerminalTabs } from '../types/terminal.const';
|
import { TerminalShortcutItems } 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';
|
||||||
|
|
||||||
// 组织默认行为的快捷键
|
// 阻止默认行为的快捷键
|
||||||
const preventKeys: Array<ShortcutKey> = [
|
const preventKeys: Array<ShortcutKey> = [
|
||||||
{
|
{
|
||||||
|
ctrlKey: true,
|
||||||
|
altKey: false,
|
||||||
|
shiftKey: true,
|
||||||
|
code: 'KeyC'
|
||||||
|
}, {
|
||||||
ctrlKey: true,
|
ctrlKey: true,
|
||||||
altKey: false,
|
altKey: false,
|
||||||
shiftKey: true,
|
shiftKey: true,
|
||||||
@@ -39,8 +44,6 @@ export default class TerminalSessionHandler implements ITerminalSessionHandler {
|
|||||||
|
|
||||||
private readonly shortcutKeys: Array<TerminalShortcutKey>;
|
private readonly shortcutKeys: Array<TerminalShortcutKey>;
|
||||||
|
|
||||||
private readonly tabManager: ITerminalTabManager;
|
|
||||||
|
|
||||||
constructor(session: ITerminalSession,
|
constructor(session: ITerminalSession,
|
||||||
domRef: TerminalDomRef) {
|
domRef: TerminalDomRef) {
|
||||||
this.session = session;
|
this.session = session;
|
||||||
@@ -49,7 +52,6 @@ export default class TerminalSessionHandler implements ITerminalSessionHandler {
|
|||||||
const { preference, tabManager } = useTerminalStore();
|
const { preference, tabManager } = useTerminalStore();
|
||||||
this.interactSetting = preference.interactSetting;
|
this.interactSetting = preference.interactSetting;
|
||||||
this.shortcutKeys = preference.shortcutSetting.keys;
|
this.shortcutKeys = preference.shortcutSetting.keys;
|
||||||
this.tabManager = tabManager;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检测是否忽略默认行为
|
// 检测是否忽略默认行为
|
||||||
@@ -94,22 +96,18 @@ export default class TerminalSessionHandler implements ITerminalSessionHandler {
|
|||||||
handler && handler.call(this);
|
handler && handler.call(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 触发快捷键
|
// 获取快捷键
|
||||||
triggerShortcutKey(e: KeyboardEvent): boolean {
|
getShortcutKey(e: KeyboardEvent) {
|
||||||
// 检测触发的快捷键
|
|
||||||
const key = this.shortcutKeys.find(key => {
|
const key = this.shortcutKeys.find(key => {
|
||||||
return key.code === e.code
|
return key.code === e.code
|
||||||
&& key.altKey === e.altKey
|
&& key.altKey === e.altKey
|
||||||
&& key.shiftKey === e.shiftKey
|
&& key.shiftKey === e.shiftKey
|
||||||
&& key.ctrlKey === e.ctrlKey;
|
&& key.ctrlKey === e.ctrlKey;
|
||||||
});
|
});
|
||||||
if (key) {
|
if (!key) {
|
||||||
// 调用处理方法
|
return undefined;
|
||||||
this.invokeHandle.call(this, key.item);
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
return TerminalShortcutItems.find(s => s.item === key.item);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 复制选中
|
// 复制选中
|
||||||
@@ -306,29 +304,4 @@ export default class TerminalSessionHandler implements ITerminalSessionHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 关闭 tab
|
|
||||||
closeTab() {
|
|
||||||
this.tabManager.deleteTab(this.session.sessionId);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 切换到前一个 tab
|
|
||||||
changeToPrevTab() {
|
|
||||||
this.tabManager.changeToPrevTab();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 切换到后一个 tab
|
|
||||||
changeToNextTab() {
|
|
||||||
this.tabManager.changeToNextTab();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 复制终端 tab
|
|
||||||
openCopyTerminalTab() {
|
|
||||||
useTerminalStore().openCopyTerminal(this.session.hostId);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 打开新建连接 tab
|
|
||||||
openNewConnectTab() {
|
|
||||||
this.tabManager.openTab(TerminalTabs.NEW_CONNECTION);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import type { TerminalPreference } from '@/store/modules/terminal/types';
|
|||||||
import type { ITerminalChannel, ITerminalSession, ITerminalSessionHandler, TerminalAddons, TerminalDomRef } from '../types/terminal.type';
|
import type { ITerminalChannel, ITerminalSession, ITerminalSessionHandler, TerminalAddons, TerminalDomRef } from '../types/terminal.type';
|
||||||
import { useTerminalStore } from '@/store';
|
import { useTerminalStore } from '@/store';
|
||||||
import { InputProtocol } from '../types/terminal.protocol';
|
import { InputProtocol } from '../types/terminal.protocol';
|
||||||
import { fontFamilySuffix, TerminalStatus } from '../types/terminal.const';
|
import { fontFamilySuffix, TerminalShortcutType, TerminalStatus } from '../types/terminal.const';
|
||||||
import { Terminal } from 'xterm';
|
import { Terminal } from 'xterm';
|
||||||
import { FitAddon } from 'xterm-addon-fit';
|
import { FitAddon } from 'xterm-addon-fit';
|
||||||
import { WebLinksAddon } from 'xterm-addon-web-links';
|
import { WebLinksAddon } from 'xterm-addon-web-links';
|
||||||
@@ -12,8 +12,8 @@ import { ImageAddon } from 'xterm-addon-image';
|
|||||||
import { CanvasAddon } from 'xterm-addon-canvas';
|
import { CanvasAddon } from 'xterm-addon-canvas';
|
||||||
import { WebglAddon } from 'xterm-addon-webgl';
|
import { WebglAddon } from 'xterm-addon-webgl';
|
||||||
import { playBell } from '@/utils/bell';
|
import { playBell } from '@/utils/bell';
|
||||||
import TerminalSessionHandler from './terminal-session-handler';
|
|
||||||
import { addEventListen } from '@/utils/event';
|
import { addEventListen } from '@/utils/event';
|
||||||
|
import TerminalSessionHandler from './terminal-session-handler';
|
||||||
|
|
||||||
// 终端会话实现
|
// 终端会话实现
|
||||||
export default class TerminalSession implements ITerminalSession {
|
export default class TerminalSession implements ITerminalSession {
|
||||||
@@ -82,16 +82,21 @@ export default class TerminalSession implements ITerminalSession {
|
|||||||
private registerShortcut(preference: UnwrapRef<TerminalPreference>) {
|
private registerShortcut(preference: UnwrapRef<TerminalPreference>) {
|
||||||
// 处理自定义按键
|
// 处理自定义按键
|
||||||
this.inst.attachCustomKeyEventHandler((e: KeyboardEvent) => {
|
this.inst.attachCustomKeyEventHandler((e: KeyboardEvent) => {
|
||||||
// 检测是否忽略默认行为
|
if (e.type !== 'keydown') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// 检测是否阻止默认行为
|
||||||
if (this.handler.checkPreventDefault(e)) {
|
if (this.handler.checkPreventDefault(e)) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
}
|
}
|
||||||
// 触发快捷键检测
|
if (preference.shortcutSetting.enabled && preference.shortcutSetting.keys.length) {
|
||||||
if (e.type === 'keydown'
|
// 获取触发的快捷键
|
||||||
&& preference.shortcutSetting.enabled
|
const shortcutKey = this.handler.getShortcutKey(e);
|
||||||
&& preference.shortcutSetting.keys.length) {
|
// 触发终端快捷键
|
||||||
// 触发快捷键
|
if (shortcutKey?.type === TerminalShortcutType.TERMINAL) {
|
||||||
return this.handler.triggerShortcutKey(e);
|
this.handler.invokeHandle.call(this.handler, shortcutKey.item);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -135,6 +135,8 @@ export interface ITerminalPanelManager<T extends TerminalPanelTabItem = Terminal
|
|||||||
setCurrentPanel: (active: number) => void;
|
setCurrentPanel: (active: number) => void;
|
||||||
// 获取面板
|
// 获取面板
|
||||||
getPanel: (index: number) => ITerminalTabManager<T>;
|
getPanel: (index: number) => ITerminalTabManager<T>;
|
||||||
|
// 移除面板
|
||||||
|
removePanel: (index: number) => void;
|
||||||
// 重置
|
// 重置
|
||||||
reset: () => void;
|
reset: () => void;
|
||||||
}
|
}
|
||||||
@@ -232,8 +234,8 @@ export interface ITerminalSessionHandler {
|
|||||||
enabledStatus: (option: string) => boolean;
|
enabledStatus: (option: string) => boolean;
|
||||||
// 调用处理方法
|
// 调用处理方法
|
||||||
invokeHandle: (option: string) => void;
|
invokeHandle: (option: string) => void;
|
||||||
// 触发快捷键
|
// 获取快捷键
|
||||||
triggerShortcutKey: (e: KeyboardEvent) => boolean;
|
getShortcutKey: (e: KeyboardEvent) => ShortcutKeyItem | undefined;
|
||||||
|
|
||||||
// 复制选中
|
// 复制选中
|
||||||
copy: () => void;
|
copy: () => void;
|
||||||
@@ -269,14 +271,4 @@ export interface ITerminalSessionHandler {
|
|||||||
screenshot: () => void;
|
screenshot: () => void;
|
||||||
// 检查追加缺失的部分
|
// 检查追加缺失的部分
|
||||||
checkAppendMissing: (value: string) => void;
|
checkAppendMissing: (value: string) => void;
|
||||||
// 关闭 tab
|
|
||||||
closeTab: () => void;
|
|
||||||
// 切换到前一个 tab
|
|
||||||
changeToPrevTab: () => void;
|
|
||||||
// 切换到后一个 tab
|
|
||||||
changeToNextTab: () => void;
|
|
||||||
// 复制终端 tab
|
|
||||||
openCopyTerminalTab: () => void;
|
|
||||||
// 打开新建连接 tab
|
|
||||||
openNewConnectTab: () => void;
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user