♻️ 修改终端交互逻辑.
This commit is contained in:
@@ -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),
|
||||
|
||||
@@ -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);
|
||||
},
|
||||
|
||||
},
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
// 主机连接状态 字典项
|
||||
export const connectStatusKey = 'hostConnectStatus';
|
||||
|
||||
// 主机连接类型 字典项
|
||||
export const connectTypeKey = 'hostConnectType';
|
||||
|
||||
// 加载的字典值
|
||||
export const dictKeys = [connectStatusKey];
|
||||
export const dictKeys = [connectStatusKey, connectTypeKey];
|
||||
|
||||
@@ -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[];
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user