🔨 回车重连.
This commit is contained in:
@@ -29,6 +29,11 @@ export default function setupPermissionGuard(router: Router) {
|
|||||||
// 页面不存在
|
// 页面不存在
|
||||||
next({ name: NOT_FOUND_ROUTER_NAME });
|
next({ name: NOT_FOUND_ROUTER_NAME });
|
||||||
}
|
}
|
||||||
|
// 修改页面标题
|
||||||
|
const locale = to.meta?.locale;
|
||||||
|
if (locale) {
|
||||||
|
document.title = locale;
|
||||||
|
}
|
||||||
NProgress.done();
|
NProgress.done();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,9 @@ export const ROOT_ROUTER: RouteRecordRaw = {
|
|||||||
export const LOGIN_ROUTER: RouteRecordRaw = {
|
export const LOGIN_ROUTER: RouteRecordRaw = {
|
||||||
path: '/login',
|
path: '/login',
|
||||||
name: LOGIN_ROUTE_NAME,
|
name: LOGIN_ROUTE_NAME,
|
||||||
|
meta: {
|
||||||
|
locale: '登录'
|
||||||
|
},
|
||||||
component: () => import('@/views/authentication/login/index.vue'),
|
component: () => import('@/views/authentication/login/index.vue'),
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -26,6 +29,7 @@ export const REDIRECT_ROUTER: RouteRecordRaw = {
|
|||||||
name: 'redirectWrapper',
|
name: 'redirectWrapper',
|
||||||
component: DEFAULT_LAYOUT,
|
component: DEFAULT_LAYOUT,
|
||||||
meta: {
|
meta: {
|
||||||
|
locale: '重定向',
|
||||||
hideInMenu: true,
|
hideInMenu: true,
|
||||||
},
|
},
|
||||||
children: [
|
children: [
|
||||||
@@ -34,6 +38,7 @@ export const REDIRECT_ROUTER: RouteRecordRaw = {
|
|||||||
name: REDIRECT_ROUTE_NAME,
|
name: REDIRECT_ROUTE_NAME,
|
||||||
component: () => import('@/views/base/redirect/index.vue'),
|
component: () => import('@/views/base/redirect/index.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
|
locale: '重定向',
|
||||||
hideInMenu: true,
|
hideInMenu: true,
|
||||||
noAffix: true
|
noAffix: true
|
||||||
},
|
},
|
||||||
@@ -45,6 +50,9 @@ export const REDIRECT_ROUTER: RouteRecordRaw = {
|
|||||||
export const FORBIDDEN_ROUTE: RouteRecordRaw = {
|
export const FORBIDDEN_ROUTE: RouteRecordRaw = {
|
||||||
path: '/403',
|
path: '/403',
|
||||||
name: FORBIDDEN_ROUTER_NAME,
|
name: FORBIDDEN_ROUTER_NAME,
|
||||||
|
meta: {
|
||||||
|
locale: '403'
|
||||||
|
},
|
||||||
component: () => import('@/views/base/status/forbidden/index.vue'),
|
component: () => import('@/views/base/status/forbidden/index.vue'),
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -53,6 +61,9 @@ export const NOT_FOUND_ROUTE: RouteRecordRaw = {
|
|||||||
// path: '/:pathMatch(.*)*',
|
// path: '/:pathMatch(.*)*',
|
||||||
path: '/404',
|
path: '/404',
|
||||||
name: NOT_FOUND_ROUTER_NAME,
|
name: NOT_FOUND_ROUTER_NAME,
|
||||||
|
meta: {
|
||||||
|
locale: '404'
|
||||||
|
},
|
||||||
component: () => import('@/views/base/status/not-found/index.vue'),
|
component: () => import('@/views/base/status/not-found/index.vue'),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -135,7 +135,7 @@ export default defineStore('terminal', {
|
|||||||
},
|
},
|
||||||
|
|
||||||
// 打开会话
|
// 打开会话
|
||||||
openSession(record: HostQueryResponse, session: PanelSessionTab, panelIndex: number = 0) {
|
openSession(record: HostQueryResponse, type: PanelSessionTab, panelIndex: number = 0) {
|
||||||
// 添加到最近连接
|
// 添加到最近连接
|
||||||
this.hosts.latestHosts = [...new Set([record.id, ...this.hosts.latestHosts])];
|
this.hosts.latestHosts = [...new Set([record.id, ...this.hosts.latestHosts])];
|
||||||
// 切换到终端面板页面
|
// 切换到终端面板页面
|
||||||
@@ -154,15 +154,31 @@ export default defineStore('terminal', {
|
|||||||
this.panelManager.getPanel(panelIndex).openTab({
|
this.panelManager.getPanel(panelIndex).openTab({
|
||||||
key: nextId(10),
|
key: nextId(10),
|
||||||
seq: nextSeq,
|
seq: nextSeq,
|
||||||
title: `(${nextSeq}) ${record.alias || record.name}`,
|
title: `(${nextSeq}) ${record.alias || record.name}`,
|
||||||
hostId: record.id,
|
hostId: record.id,
|
||||||
address: record.address,
|
address: record.address,
|
||||||
color: record.color,
|
color: record.color,
|
||||||
icon: session.icon,
|
icon: type.icon,
|
||||||
type: session.type
|
type: type.type
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// 重新打开 terminal 会话
|
||||||
|
async reOpenTerminal(hostId: number, sessionId: string, panelIndex: number = 0) {
|
||||||
|
console.log('rec');
|
||||||
|
// 添加到最近连接
|
||||||
|
this.hosts.latestHosts = [...new Set([hostId, ...this.hosts.latestHosts])];
|
||||||
|
// 切换到终端面板页面
|
||||||
|
this.tabManager.openTab(TerminalTabs.TERMINAL_PANEL);
|
||||||
|
// 获取当前面板并且分配新的 sessionId
|
||||||
|
const panel = this.panelManager.getPanel(panelIndex);
|
||||||
|
const tab = panel.getTab(sessionId);
|
||||||
|
const newSessionId = nextId(10);
|
||||||
|
tab.key = newSessionId;
|
||||||
|
// 重新打开 ssh
|
||||||
|
await this.sessionManager.reOpenSsh(sessionId, newSessionId);
|
||||||
|
},
|
||||||
|
|
||||||
// 复制并且打开会话
|
// 复制并且打开会话
|
||||||
copySession(item: TerminalPanelTabItem, panelIndex: number = 0) {
|
copySession(item: TerminalPanelTabItem, panelIndex: number = 0) {
|
||||||
const host = this.hosts.hostList
|
const host = this.hosts.hostList
|
||||||
|
|||||||
@@ -60,7 +60,7 @@
|
|||||||
{{ dateFormat(new Date(record.startTime)) }}
|
{{ dateFormat(new Date(record.startTime)) }}
|
||||||
</a-descriptions-item>
|
</a-descriptions-item>
|
||||||
<!-- 结束时间 -->
|
<!-- 结束时间 -->
|
||||||
<a-descriptions-item label="结束时间">
|
<a-descriptions-item v-if="record.endTime" label="结束时间">
|
||||||
{{ dateFormat(new Date(record.endTime)) }}
|
{{ dateFormat(new Date(record.endTime)) }}
|
||||||
</a-descriptions-item>
|
</a-descriptions-item>
|
||||||
<!-- traceId -->
|
<!-- traceId -->
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
</span>
|
</span>
|
||||||
</a-space>
|
</a-space>
|
||||||
</template>
|
</template>
|
||||||
<!-- 终端面板 -->
|
<!-- 终端面板 FIXME -->
|
||||||
<a-tab-pane v-for="tab in panel.items"
|
<a-tab-pane v-for="tab in panel.items"
|
||||||
:key="tab.key">
|
:key="tab.key">
|
||||||
<!-- 标题 -->
|
<!-- 标题 -->
|
||||||
@@ -54,8 +54,8 @@
|
|||||||
import SftpView from '../sftp/sftp-view.vue';
|
import SftpView from '../sftp/sftp-view.vue';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
index: number,
|
index: number;
|
||||||
panel: ITerminalTabManager<TerminalPanelTabItem>,
|
panel: ITerminalTabManager<TerminalPanelTabItem>;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const emits = defineEmits(['close', 'openNewConnect']);
|
const emits = defineEmits(['close', 'openNewConnect']);
|
||||||
|
|||||||
@@ -137,6 +137,7 @@
|
|||||||
|
|
||||||
// 初始化会话
|
// 初始化会话
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
|
console.log('onMounted', props.tab.key);
|
||||||
// 创建终端处理器
|
// 创建终端处理器
|
||||||
session.value = await sessionManager.openSsh(props.tab, {
|
session.value = await sessionManager.openSsh(props.tab, {
|
||||||
el: terminalRef.value,
|
el: terminalRef.value,
|
||||||
|
|||||||
@@ -85,6 +85,7 @@ export default class SshSession implements ISshSession {
|
|||||||
if (e.type !== 'keydown') {
|
if (e.type !== 'keydown') {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
console.log(e);
|
||||||
// 检测是否为内置快捷键
|
// 检测是否为内置快捷键
|
||||||
if (this.handler.checkIsBuiltin(e)) {
|
if (this.handler.checkIsBuiltin(e)) {
|
||||||
return true;
|
return true;
|
||||||
@@ -93,6 +94,13 @@ export default class SshSession implements ISshSession {
|
|||||||
if (this.handler.checkPreventDefault(e)) {
|
if (this.handler.checkPreventDefault(e)) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
}
|
}
|
||||||
|
if (e.key === 'Enter') {
|
||||||
|
console.log("enter start");
|
||||||
|
// TODO 回车 重新连接
|
||||||
|
useTerminalStore().reOpenTerminal(this.hostId, this.sessionId);
|
||||||
|
console.log("enter end");
|
||||||
|
}
|
||||||
|
// 自定义快捷键
|
||||||
if (preference.shortcutSetting.enabled && preference.shortcutSetting.keys.length) {
|
if (preference.shortcutSetting.enabled && preference.shortcutSetting.keys.length) {
|
||||||
// 获取触发的快捷键
|
// 获取触发的快捷键
|
||||||
const shortcutKey = this.handler.getShortcutKey(e);
|
const shortcutKey = this.handler.getShortcutKey(e);
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ export default class TerminalChannel implements ITerminalChannel {
|
|||||||
|
|
||||||
// 发送消息
|
// 发送消息
|
||||||
send(protocol: Protocol, payload: InputPayload): void {
|
send(protocol: Protocol, payload: InputPayload): void {
|
||||||
|
console.log('send', payload);
|
||||||
// 检查是否连接
|
// 检查是否连接
|
||||||
if (!this.isConnected()) {
|
if (!this.isConnected()) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ export default class TerminalOutputProcessor implements ITerminalOutputProcessor
|
|||||||
}
|
}
|
||||||
if (session instanceof SshSession) {
|
if (session instanceof SshSession) {
|
||||||
// ssh 拼接关闭消息
|
// ssh 拼接关闭消息
|
||||||
session.write(`\r\n[91m${msg || ''}[0m`);
|
session.write(`\r\n\r\n[91m${msg || ''}[0m\r\n\r\n`);
|
||||||
// 设置状态
|
// 设置状态
|
||||||
session.status = TerminalStatus.CLOSED;
|
session.status = TerminalStatus.CLOSED;
|
||||||
session.connected = false;
|
session.connected = false;
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import type {
|
|||||||
TerminalTabItem,
|
TerminalTabItem,
|
||||||
XtermDomRef
|
XtermDomRef
|
||||||
} from '../types/terminal.type';
|
} from '../types/terminal.type';
|
||||||
|
import type { ISshSession } from '../types/terminal.type';
|
||||||
import { sleep } from '@/utils';
|
import { sleep } from '@/utils';
|
||||||
import { InputProtocol } from '../types/terminal.protocol';
|
import { InputProtocol } from '../types/terminal.protocol';
|
||||||
import { PanelSessionType } from '../types/terminal.const';
|
import { PanelSessionType } from '../types/terminal.const';
|
||||||
@@ -34,8 +35,7 @@ export default class TerminalSessionManager implements ITerminalSessionManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 打开 ssh 会话
|
// 打开 ssh 会话
|
||||||
async openSsh(tab: TerminalTabItem,
|
async openSsh(tab: TerminalTabItem, domRef: XtermDomRef) {
|
||||||
domRef: XtermDomRef) {
|
|
||||||
const sessionId = tab.key;
|
const sessionId = tab.key;
|
||||||
const hostId = tab.hostId as number;
|
const hostId = tab.hostId as number;
|
||||||
// 初始化客户端
|
// 初始化客户端
|
||||||
@@ -61,6 +61,25 @@ export default class TerminalSessionManager implements ITerminalSessionManager {
|
|||||||
return session;
|
return session;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 重新打开 ssh 会话
|
||||||
|
async reOpenSsh(sessionId: string, newSessionId: string): Promise<void> {
|
||||||
|
console.log('sessionId', sessionId, 'newSessionId', newSessionId);
|
||||||
|
// 初始化客户端
|
||||||
|
await this.initChannel();
|
||||||
|
// 获取会话并且重新设置 sessionId
|
||||||
|
const session = this.sessions[sessionId] as ISshSession;
|
||||||
|
session.sessionId = newSessionId;
|
||||||
|
this.sessions[sessionId] = undefined as unknown as ISshSession;
|
||||||
|
this.sessions[newSessionId] = session;
|
||||||
|
console.log('ckckck');
|
||||||
|
// 发送会话初始化请求
|
||||||
|
this.channel.send(InputProtocol.CHECK, {
|
||||||
|
sessionId: newSessionId,
|
||||||
|
hostId: session.hostId,
|
||||||
|
connectType: PanelSessionType.SSH.type
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// 打开 sftp 会话
|
// 打开 sftp 会话
|
||||||
async openSftp(tab: TerminalTabItem, resolver: ISftpSessionResolver): Promise<ISftpSession> {
|
async openSftp(tab: TerminalTabItem, resolver: ISftpSessionResolver): Promise<ISftpSession> {
|
||||||
const sessionId = tab.key;
|
const sessionId = tab.key;
|
||||||
|
|||||||
@@ -25,6 +25,11 @@ export default class TerminalTabManager<T extends TerminalTabItem = TerminalTabI
|
|||||||
return this.items.find(s => s.key === this.active);
|
return this.items.find(s => s.key === this.active);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 获取 tab
|
||||||
|
getTab(key: string): T {
|
||||||
|
return this.items.find(s => s.key === key) as T;
|
||||||
|
}
|
||||||
|
|
||||||
// 点击 tab
|
// 点击 tab
|
||||||
clickTab(key: string): void {
|
clickTab(key: string): void {
|
||||||
this.active = key;
|
this.active = key;
|
||||||
|
|||||||
@@ -112,6 +112,8 @@ export interface ITerminalTabManager<T extends TerminalTabItem = TerminalTabItem
|
|||||||
|
|
||||||
// 获取当前 tab
|
// 获取当前 tab
|
||||||
getCurrentTab: () => T | undefined;
|
getCurrentTab: () => T | undefined;
|
||||||
|
// 获取 tab
|
||||||
|
getTab: (key: string) => T;
|
||||||
// 点击 tab
|
// 点击 tab
|
||||||
clickTab: (key: string) => void;
|
clickTab: (key: string) => void;
|
||||||
// 删除 tab
|
// 删除 tab
|
||||||
@@ -151,6 +153,8 @@ export interface ITerminalPanelManager<T extends TerminalPanelTabItem = Terminal
|
|||||||
export interface ITerminalSessionManager {
|
export interface ITerminalSessionManager {
|
||||||
// 打开 ssh 会话
|
// 打开 ssh 会话
|
||||||
openSsh: (tab: TerminalTabItem, domRef: XtermDomRef) => Promise<ISshSession>;
|
openSsh: (tab: TerminalTabItem, domRef: XtermDomRef) => Promise<ISshSession>;
|
||||||
|
// 重新打开 ssh 会话
|
||||||
|
reOpenSsh: (sessionId: string, newSessionId: string) => Promise<void>;
|
||||||
// 打开 sftp 会话
|
// 打开 sftp 会话
|
||||||
openSftp: (tab: TerminalTabItem, resolver: ISftpSessionResolver) => Promise<ISftpSession>;
|
openSftp: (tab: TerminalTabItem, resolver: ISftpSessionResolver) => Promise<ISftpSession>;
|
||||||
// 获取终端会话
|
// 获取终端会话
|
||||||
|
|||||||
Reference in New Issue
Block a user