♻️ 修改终端交互逻辑.

This commit is contained in:
lijiahang
2024-02-05 11:51:25 +08:00
parent b4ceb3839c
commit 13786bbc7c
11 changed files with 105 additions and 78 deletions

View File

@@ -66,13 +66,13 @@ public class TerminalPreferenceStrategy implements IPreferenceStrategy<TerminalP
new TerminalPreferenceModel.ShortcutKeysModel("changeToPrevTab", true, true, true, "BracketLeft", true),
new TerminalPreferenceModel.ShortcutKeysModel("changeToNextTab", true, true, true, "BracketRight", true),
new TerminalPreferenceModel.ShortcutKeysModel("openNewConnectTab", true, true, true, "KeyN", true),
// 终端面板快捷键
// 会话快捷键
new TerminalPreferenceModel.ShortcutKeysModel("openNewConnectModal", true, false, true, "KeyN", true),
new TerminalPreferenceModel.ShortcutKeysModel("copyTerminal", true, false, true, "KeyO", true),
new TerminalPreferenceModel.ShortcutKeysModel("closeTerminal", true, false, true, "KeyW", true),
new TerminalPreferenceModel.ShortcutKeysModel("changeToPrevTerminal", true, false, true, "BracketLeft", true),
new TerminalPreferenceModel.ShortcutKeysModel("changeToNextTerminal", true, false, true, "BracketRight", true),
// 终端会话快捷键
new TerminalPreferenceModel.ShortcutKeysModel("copySession", true, false, true, "KeyO", true),
new TerminalPreferenceModel.ShortcutKeysModel("closeSession", true, false, true, "KeyW", true),
new TerminalPreferenceModel.ShortcutKeysModel("changeToPrevSession", true, false, true, "BracketLeft", true),
new TerminalPreferenceModel.ShortcutKeysModel("changeToNextSession", true, false, true, "BracketRight", true),
// 终端快捷键
new TerminalPreferenceModel.ShortcutKeysModel("copy", true, true, false, "KeyC", true),
new TerminalPreferenceModel.ShortcutKeysModel("paste", true, true, false, "KeyV", true),
new TerminalPreferenceModel.ShortcutKeysModel("toTop", true, true, false, "ArrowUp", true),

View File

@@ -8,6 +8,7 @@ import type {
TerminalShortcutSetting,
TerminalState
} from './types';
import type { PanelSessionTab, TerminalPanelTabItem } from '@/views/host/terminal/types/terminal.type';
import type { AuthorizedHostQueryResponse } from '@/api/asset/asset-authorized-data';
import { getCurrentAuthorizedHost } from '@/api/asset/asset-authorized-data';
import type { HostQueryResponse } from '@/api/asset/host';
@@ -17,7 +18,7 @@ import { defineStore } from 'pinia';
import { getPreference, updatePreference } from '@/api/user/preference';
import { nextSessionId } from '@/utils';
import { Message } from '@arco-design/web-vue';
import { TerminalPanelTabType, TerminalTabs } from '@/views/host/terminal/types/terminal.const';
import { PanelSessionType, 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';
import TerminalPanelManager from '@/views/host/terminal/handler/terminal-panel-manager';
@@ -131,8 +132,8 @@ export default defineStore('terminal', {
});
},
// 打开终端
openTerminal(record: HostQueryResponse, panelIndex: number = 0) {
// 打开会话
openSession(record: HostQueryResponse, session: PanelSessionTab, panelIndex: number = 0) {
// 添加到最近连接
this.hosts.latestHosts = [...new Set([record.id, ...this.hosts.latestHosts])];
// 切换到终端面板页面
@@ -154,17 +155,21 @@ export default defineStore('terminal', {
title: `(${nextSeq}) ${record.alias || record.name}`,
hostId: record.id,
address: record.address,
icon: 'icon-desktop',
type: TerminalPanelTabType.TERMINAL
icon: session.icon,
type: session.type
});
},
// 复制并且打开终端
copyTerminalSession(hostId: number, panelIndex: number = 0) {
// 复制并且打开会话
copySession(item: TerminalPanelTabItem, panelIndex: number = 0) {
const host = this.hosts.hostList
.find(s => s.id === hostId);
.find(s => s.id === item.hostId);
if (host) {
this.openTerminal(host, panelIndex);
const sessionType = {
type: item.type,
icon: item.icon
};
this.openSession(host, sessionType, panelIndex);
}
},
@@ -189,14 +194,14 @@ export default defineStore('terminal', {
// 获取当前终端会话
getCurrentTerminalSession() {
// 获取面板会话
const panelTab = this.panelManager
const sessionTab = this.panelManager
.getCurrentPanel()
.getCurrentTab();
if (!panelTab || panelTab.type !== TerminalPanelTabType.TERMINAL) {
if (!sessionTab || sessionTab.type !== PanelSessionType.TERMINAL.type) {
return;
}
// 获取会话
return this.sessionManager.getSession(panelTab.key);
return this.sessionManager.getSession(sessionTab.key);
},
},

View File

@@ -2,11 +2,11 @@
<!-- 搜索 -->
<a-card class="general-card table-search-card">
<query-header :model="formModel"
label-align="left"
:itemOptions="{ 5: { span: 2 } }"
@submit="fetchTableData"
@reset="fetchTableData"
@keyup.enter="() => fetchTableData()">
label-align="left"
:itemOptions="{ 6: { span: 2 } }"
@submit="fetchTableData"
@reset="fetchTableData"
@keyup.enter="() => fetchTableData()">
<!-- 连接用户 -->
<a-form-item field="userId" label="连接用户" label-col-flex="50px">
<user-selector v-model="formModel.userId"
@@ -30,6 +30,13 @@
:options="toOptions(connectStatusKey)"
allow-clear />
</a-form-item>
<!-- 类型 -->
<a-form-item field="type" label="类型" label-col-flex="50px">
<a-select v-model="formModel.type"
placeholder="请选择类型"
:options="toOptions(connectTypeKey)"
allow-clear />
</a-form-item>
<!-- token -->
<a-form-item field="token" label="token" label-col-flex="50px">
<a-input v-model="formModel.token" placeholder="请输入token" allow-clear />
@@ -107,7 +114,7 @@
import { getHostConnectLogPage } from '@/api/asset/host-connect-log';
import useLoading from '@/hooks/loading';
import columns from '../types/table.columns';
import { connectStatusKey } from '../types/const';
import { connectStatusKey, connectTypeKey } from '../types/const';
import { usePagination } from '@/types/table';
import { useDictStore } from '@/store';
import useCopy from '@/hooks/copy';

View File

@@ -1,5 +1,8 @@
// 主机连接状态 字典项
export const connectStatusKey = 'hostConnectStatus';
// 主机连接类型 字典项
export const connectTypeKey = 'hostConnectType';
// 加载的字典值
export const dictKeys = [connectStatusKey];
export const dictKeys = [connectStatusKey, connectTypeKey];

View File

@@ -31,13 +31,11 @@ const columns = [
ellipsis: true,
tooltip: true,
}, {
title: 'token',
dataIndex: 'token',
slotName: 'token',
title: '类型',
dataIndex: 'type',
slotName: 'type',
width: 68,
align: 'left',
width: 180,
ellipsis: true,
tooltip: true,
}, {
title: '状态',
dataIndex: 'status',
@@ -45,22 +43,23 @@ const columns = [
align: 'left',
width: 90,
}, {
title: '开始时间',
dataIndex: 'startTime',
slotName: 'startTime',
title: 'token',
dataIndex: 'token',
slotName: 'token',
align: 'left',
width: 180,
render: ({ record }) => {
return record.startTime && dateFormat(new Date(record.startTime));
},
width: 120,
ellipsis: true,
tooltip: true,
}, {
title: '结束时间',
dataIndex: 'endTime',
slotName: 'endTime',
title: '连接时间',
dataIndex: 'connectTime',
slotName: 'connectTime',
align: 'left',
width: 180,
width: 310,
render: ({ record }) => {
return record.endTime && dateFormat(new Date(record.endTime));
return (record.startTime && dateFormat(new Date(record.startTime)))
+ ' - '
+ (record.endTime && dateFormat(new Date(record.endTime)) || '现在');
},
},
] as TableColumnData[];

View File

@@ -32,10 +32,10 @@
import type { HostQueryResponse } from '@/api/asset/host';
import { onMounted, ref } from 'vue';
import { useTerminalStore } from '@/store';
import { TerminalTabs } from '../../types/terminal.const';
import { PanelSessionType, TerminalTabs } from '../../types/terminal.const';
const totalCount = 7;
const { tabManager, hosts, openTerminal } = useTerminalStore();
const { tabManager, hosts, openSession } = useTerminalStore();
const combinedHandlers = ref<Array<CombinedHandlerItem>>([{
title: TerminalTabs.NEW_CONNECTION.title,
@@ -46,8 +46,8 @@
// 点击组合操作元素
const clickHandlerItem = (item: CombinedHandlerItem) => {
if (item.host) {
// 打开终端
openTerminal(item.host as HostQueryResponse);
// 打开会话
openSession(item.host as HostQueryResponse, PanelSessionType.TERMINAL);
} else {
// 打开 tab
tabManager.openTab(item.tab as TerminalTabItem);

View File

@@ -45,7 +45,7 @@
import type { ITerminalTabManager, TerminalPanelTabItem } from '../../types/terminal.type';
import { watch } from 'vue';
import { useTerminalStore } from '@/store';
import { TerminalPanelTabType } from '../../types/terminal.const';
import { PanelSessionType } from '../../types/terminal.const';
import TerminalView from '../xterm/terminal-view.vue';
const props = defineProps<{
@@ -62,14 +62,14 @@
// 失焦自动终端
if (before) {
const beforeTab = props.panel.items.find(s => s.key === before);
if (beforeTab && beforeTab?.type === TerminalPanelTabType.TERMINAL) {
if (beforeTab && beforeTab?.type === PanelSessionType.TERMINAL.type) {
sessionManager.getSession(before)?.blur();
}
}
// 终端自动聚焦
if (active) {
const activeTab = props.panel.items.find(s => s.key === active);
if (activeTab && activeTab?.type === TerminalPanelTabType.TERMINAL) {
if (activeTab && activeTab?.type === PanelSessionType.TERMINAL.type) {
sessionManager.getSession(active)?.focus();
}
}

View File

@@ -26,7 +26,7 @@
import TerminalPanel from './terminal-panel.vue';
import HostListModal from '../new-connection/host-list-modal.vue';
const { preference, tabManager, panelManager, copyTerminalSession } = useTerminalStore();
const { preference, tabManager, panelManager, copySession } = useTerminalStore();
const hostModal = ref();
@@ -67,10 +67,10 @@
hostModal.value.open(panelManager.active);
break;
case TerminalShortcutKeys.COPY_TERMINAL:
// 复制终端
const hostId = panelManager.getCurrentPanel().getCurrentTab()?.hostId;
if (hostId) {
copyTerminalSession(hostId, panelManager.active);
// 复制会话
const currentTab = panelManager.getCurrentPanel().getCurrentTab();
if (currentTab) {
copySession(currentTab, panelManager.active);
}
break;
case TerminalShortcutKeys.CLOSE_TERMINAL:
@@ -80,11 +80,11 @@
panel.deleteTab(panel.active);
}
break;
case TerminalShortcutKeys.CHANGE_TO_PREV_TERMINAL:
case TerminalShortcutKeys.CHANGE_TO_PREV_SESSION:
// 切换至前一个终端
panelManager.getCurrentPanel().changeToPrevTab();
break;
case TerminalShortcutKeys.CHANGE_TO_NEXT_TERMINAL:
case TerminalShortcutKeys.CHANGE_TO_NEXT_SESSION:
// 切换至后一个终端
panelManager.getCurrentPanel().changeToNextTab();
break;

View File

@@ -52,9 +52,10 @@
import type { HostQueryResponse } from '@/api/asset/host';
import { computed, ref } from 'vue';
import { useTerminalStore } from '@/store';
import { PanelSessionType } from '../../types/terminal.const';
import useVisible from '@/hooks/visible';
const { hosts, openTerminal } = useTerminalStore();
const { hosts, openSession } = useTerminalStore();
const { visible, setVisible } = useVisible();
const panelIndex = ref();
@@ -97,7 +98,7 @@
// 打开终端
const clickHost = (item: HostQueryResponse) => {
openTerminal(item, panelIndex.value);
openSession(item, PanelSessionType.TERMINAL, panelIndex.value);
setVisible(false);
};

View File

@@ -20,13 +20,13 @@
<!-- 左侧图标-名称 -->
<div class="flex-center host-item-left">
<!-- 图标 -->
<span class="host-item-left-icon" @click="openTerminal(item)">
<icon-desktop />
</span>
<span class="host-item-left-icon">
<icon-desktop />
</span>
<!-- 名称 -->
<span class="host-item-left-name">
<!-- 名称文本 -->
<template v-if="!item.editable">
<!-- 名称文本 -->
<template v-if="!item.editable">
<!-- 文本 -->
<a-tooltip position="top"
:mini="true"
@@ -42,7 +42,7 @@
</template>
</span>
</a-tooltip>
<!-- 修改别名 -->
<!-- 修改别名 -->
<a-tooltip position="top"
:mini="true"
:auto-fix-position="false"
@@ -54,7 +54,7 @@
</a-tooltip>
</template>
<!-- 名称输入框 -->
<template v-else>
<template v-else>
<a-input v-model="item.alias"
ref="aliasNameInput"
class="host-item-left-name-input"
@@ -76,7 +76,7 @@
</template>
</a-input>
</template>
</span>
</span>
</div>
<!-- 中间ip -->
<div class="flex-center host-item-center">
@@ -111,19 +111,32 @@
</div>
<!-- 操作 -->
<div class="host-item-right-actions">
<!-- 连接主机 -->
<!-- 打开 SSH -->
<a-tooltip position="top"
:mini="true"
:auto-fix-position="false"
content-class="terminal-tooltip-content"
arrow-class="terminal-tooltip-content"
content="连接主机">
content="打开 SSH">
<div class="terminal-sidebar-icon-wrapper">
<div class="terminal-sidebar-icon" @click="openTerminal(item)">
<div class="terminal-sidebar-icon" @click="openSession(item, PanelSessionType.TERMINAL)">
<icon-thunderbolt />
</div>
</div>
</a-tooltip>
<!-- 打开 SFTP -->
<a-tooltip position="top"
:mini="true"
:auto-fix-position="false"
content-class="terminal-tooltip-content"
arrow-class="terminal-tooltip-content"
content="打开 SFTP">
<div class="terminal-sidebar-icon-wrapper">
<div class="terminal-sidebar-icon" @click="openSession(item, PanelSessionType.SFTP)">
<icon-folder />
</div>
</div>
</a-tooltip>
<!-- 连接设置 -->
<a-tooltip position="top"
:mini="true"
@@ -172,7 +185,7 @@
import { dataColor } from '@/utils';
import { tagColor } from '@/views/asset/host-list/types/const';
import { updateHostAlias } from '@/api/asset/host-extra';
import { openSshModalKey } from '../../types/terminal.const';
import { openSshModalKey, PanelSessionType } from '../../types/terminal.const';
import { useTerminalStore } from '@/store';
const props = defineProps<{
@@ -180,7 +193,7 @@
emptyValue: string
}>();
const { openTerminal } = useTerminalStore();
const { openSession } = useTerminalStore();
const { toggle: toggleFavorite, loading: favoriteLoading } = useFavorite('HOST');
const aliasNameInput = ref();
@@ -311,7 +324,6 @@
border-radius: 32px;
margin-right: 10px;
font-size: 16px;
cursor: pointer;
display: flex;
justify-content: center;
align-items: center;

View File

@@ -26,15 +26,15 @@
@set-editable="setEditableStatus"
@clear-editable="clearEditableStatus"
@update-enabled="updateEnabledStatus" />
<!-- 终端面板快捷键 -->
<terminal-shortcut-keys-block title="终端面板快捷键"
:type="TerminalShortcutType.PANEL"
<!-- 会话快捷键 -->
<terminal-shortcut-keys-block title="会话快捷键"
:type="TerminalShortcutType.SESSION"
:items="shortcutKeys"
@set-editable="setEditableStatus"
@clear-editable="clearEditableStatus"
@update-enabled="updateEnabledStatus" />
<!-- 终端会话快捷键 -->
<terminal-shortcut-keys-block title="终端会话快捷键"
<!-- 终端快捷键 -->
<terminal-shortcut-keys-block title="终端快捷键"
:type="TerminalShortcutType.TERMINAL"
:items="shortcutKeys"
@set-editable="setEditableStatus"