🔨 优化代码逻辑.
This commit is contained in:
@@ -13,7 +13,7 @@
|
|||||||
ref="formRef"
|
ref="formRef"
|
||||||
label-align="right"
|
label-align="right"
|
||||||
:auto-label-width="true"
|
:auto-label-width="true"
|
||||||
:rules="formRules">
|
:rules="commandSnippetFormRules">
|
||||||
<!-- 名称 -->
|
<!-- 名称 -->
|
||||||
<a-form-item field="name" label="名称">
|
<a-form-item field="name" label="名称">
|
||||||
<a-input v-model="formModel.name"
|
<a-input v-model="formModel.name"
|
||||||
@@ -52,8 +52,8 @@
|
|||||||
import { createCommandSnippet, updateCommandSnippet } from '@/api/terminal/command-snippet';
|
import { createCommandSnippet, updateCommandSnippet } from '@/api/terminal/command-snippet';
|
||||||
import useLoading from '@/hooks/loading';
|
import useLoading from '@/hooks/loading';
|
||||||
import useVisible from '@/hooks/visible';
|
import useVisible from '@/hooks/visible';
|
||||||
import formRules from './types/form.rules';
|
|
||||||
import { Message } from '@arco-design/web-vue';
|
import { Message } from '@arco-design/web-vue';
|
||||||
|
import { commandSnippetFormRules } from '../../types/form.rules';
|
||||||
import CommandSnippetGroupSelector from '@/components/terminal/command-snippet/gruop/selector/index.vue';
|
import CommandSnippetGroupSelector from '@/components/terminal/command-snippet/gruop/selector/index.vue';
|
||||||
|
|
||||||
const { visible, setVisible } = useVisible();
|
const { visible, setVisible } = useVisible();
|
||||||
|
|||||||
@@ -1,24 +0,0 @@
|
|||||||
import type { FieldRule } from '@arco-design/web-vue';
|
|
||||||
|
|
||||||
export const groupId = [{
|
|
||||||
message: '请选择分组'
|
|
||||||
}] as FieldRule[];
|
|
||||||
|
|
||||||
export const name = [{
|
|
||||||
required: true,
|
|
||||||
message: '请输入名称'
|
|
||||||
}, {
|
|
||||||
maxLength: 64,
|
|
||||||
message: '名称长度不能大于64位'
|
|
||||||
}] as FieldRule[];
|
|
||||||
|
|
||||||
export const command = [{
|
|
||||||
required: true,
|
|
||||||
message: '请输入代码片段'
|
|
||||||
}] as FieldRule[];
|
|
||||||
|
|
||||||
export default {
|
|
||||||
groupId,
|
|
||||||
name,
|
|
||||||
command,
|
|
||||||
} as Record<string, FieldRule | FieldRule[]>;
|
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
ref="formRef"
|
ref="formRef"
|
||||||
label-align="right"
|
label-align="right"
|
||||||
:auto-label-width="true"
|
:auto-label-width="true"
|
||||||
:rules="formRules">
|
:rules="bookmarkFormRules">
|
||||||
<!-- 名称 -->
|
<!-- 名称 -->
|
||||||
<a-form-item field="name" label="名称">
|
<a-form-item field="name" label="名称">
|
||||||
<a-input v-model="formModel.name"
|
<a-input v-model="formModel.name"
|
||||||
@@ -54,12 +54,11 @@
|
|||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
import useLoading from '@/hooks/loading';
|
import useLoading from '@/hooks/loading';
|
||||||
import useVisible from '@/hooks/visible';
|
import useVisible from '@/hooks/visible';
|
||||||
import formRules from './types/form.rules';
|
|
||||||
import { createPathBookmark, updatePathBookmark } from '@/api/terminal/path-bookmark';
|
import { createPathBookmark, updatePathBookmark } from '@/api/terminal/path-bookmark';
|
||||||
import { PathBookmarkType } from './types/const';
|
import { bookmarkFormRules } from '../../types/form.rules';
|
||||||
|
import { pathBookmarkTypeKey, PathBookmarkType } from '../../types/const';
|
||||||
import { useDictStore } from '@/store';
|
import { useDictStore } from '@/store';
|
||||||
import { Message } from '@arco-design/web-vue';
|
import { Message } from '@arco-design/web-vue';
|
||||||
import { pathBookmarkTypeKey } from '../../types/const';
|
|
||||||
import PathBookmarkGroupSelector from '@/components/terminal/bookmark-path/group/selector/index.vue';
|
import PathBookmarkGroupSelector from '@/components/terminal/bookmark-path/group/selector/index.vue';
|
||||||
|
|
||||||
const { visible, setVisible } = useVisible();
|
const { visible, setVisible } = useVisible();
|
||||||
|
|||||||
@@ -117,8 +117,7 @@
|
|||||||
import { useTerminalStore } from '@/store';
|
import { useTerminalStore } from '@/store';
|
||||||
import { useDebounceFn } from '@vueuse/core';
|
import { useDebounceFn } from '@vueuse/core';
|
||||||
import { getParentPath } from '@/utils/file';
|
import { getParentPath } from '@/utils/file';
|
||||||
import { PathBookmarkType } from './types/const';
|
import { TerminalSessionTypes, PathBookmarkType } from '../../types/const';
|
||||||
import { TerminalSessionTypes } from '../../types/const';
|
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
item: PathBookmarkQueryResponse;
|
item: PathBookmarkQueryResponse;
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
// 路径书签类型
|
|
||||||
export const PathBookmarkType = {
|
|
||||||
FILE: 'FILE',
|
|
||||||
DIR: 'DIR',
|
|
||||||
};
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
import type { FieldRule } from '@arco-design/web-vue';
|
|
||||||
|
|
||||||
export const groupId = [{
|
|
||||||
message: '请选择分组'
|
|
||||||
}] as FieldRule[];
|
|
||||||
|
|
||||||
export const name = [{
|
|
||||||
required: true,
|
|
||||||
message: '请输入名称'
|
|
||||||
}, {
|
|
||||||
maxLength: 64,
|
|
||||||
message: '名称长度不能大于64位'
|
|
||||||
}] as FieldRule[];
|
|
||||||
|
|
||||||
export const type = [{
|
|
||||||
required: true,
|
|
||||||
message: '请选择类型'
|
|
||||||
}] as FieldRule[];
|
|
||||||
|
|
||||||
export const path = [{
|
|
||||||
required: true,
|
|
||||||
message: '请输入路径'
|
|
||||||
}, {
|
|
||||||
maxLength: 1000,
|
|
||||||
message: '名称长度不能大于1000位'
|
|
||||||
}] as FieldRule[];
|
|
||||||
|
|
||||||
export default {
|
|
||||||
groupId,
|
|
||||||
name,
|
|
||||||
type,
|
|
||||||
path,
|
|
||||||
} as Record<string, FieldRule | FieldRule[]>;
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div v-if="session.status.connectStatus === TerminalStatus.CONNECTED">
|
<div v-if="session.state.connectStatus === TerminalStatus.CONNECTED">
|
||||||
<!-- 工具栏 -->
|
<!-- 工具栏 -->
|
||||||
<a-popover v-model:popup-visible="visible"
|
<a-popover v-model:popup-visible="visible"
|
||||||
:title="undefined"
|
:title="undefined"
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
<template>
|
<template>
|
||||||
<div v-if="session.status.connectStatus !== TerminalStatus.CONNECTED && visible">
|
<div v-if="session.state.connectStatus !== TerminalStatus.CONNECTED && visible">
|
||||||
<!-- 连接中 -->
|
<!-- 连接中 -->
|
||||||
<a-spin v-if="session.status.connectStatus === TerminalStatus.CONNECTING"
|
<a-spin v-if="session.state.connectStatus === TerminalStatus.CONNECTING"
|
||||||
tip="正在连接会话..."
|
tip="正在连接会话..."
|
||||||
dot />
|
dot />
|
||||||
<!-- 会话关闭 -->
|
<!-- 会话关闭 -->
|
||||||
<a-card v-if="session.status.connectStatus === TerminalStatus.CLOSED"
|
<a-card v-if="session.state.connectStatus === TerminalStatus.CLOSED"
|
||||||
class="rdp-status-wrapper"
|
class="rdp-status-wrapper"
|
||||||
title="会话已关闭">
|
title="会话已关闭">
|
||||||
<!-- 错误信息 -->
|
<!-- 错误信息 -->
|
||||||
@@ -20,18 +20,18 @@
|
|||||||
</a-descriptions-item>
|
</a-descriptions-item>
|
||||||
<!-- 错误码 -->
|
<!-- 错误码 -->
|
||||||
<a-descriptions-item label="错误码">
|
<a-descriptions-item label="错误码">
|
||||||
{{ session.status.closeCode }}
|
{{ session.state.closeCode }}
|
||||||
</a-descriptions-item>
|
</a-descriptions-item>
|
||||||
<!-- 错误信息 -->
|
<!-- 错误信息 -->
|
||||||
<a-descriptions-item label="错误信息">
|
<a-descriptions-item label="错误信息">
|
||||||
<span class="span-red">
|
<span class="span-red">
|
||||||
<!-- 异地登录 -->
|
<!-- 异地登录 -->
|
||||||
<template v-if="session.status.closeCode === TerminalCloseCode.LOGGED_ELSEWHERE">
|
<template v-if="session.state.closeCode === TerminalCloseCode.LOGGED_ELSEWHERE">
|
||||||
{{ TerminalMessages.loggedElsewhere }} ({{ dateFormat() }})
|
{{ TerminalMessages.loggedElsewhere }} ({{ dateFormat() }})
|
||||||
</template>
|
</template>
|
||||||
<!-- 其他错误 -->
|
<!-- 其他错误 -->
|
||||||
<template v-else>
|
<template v-else>
|
||||||
{{ session.status.closeMessage ?? '-' }}
|
{{ session.state.closeMessage ?? '-' }}
|
||||||
</template>
|
</template>
|
||||||
</span>
|
</span>
|
||||||
</a-descriptions-item>
|
</a-descriptions-item>
|
||||||
@@ -39,7 +39,7 @@
|
|||||||
<!-- 按钮 -->
|
<!-- 按钮 -->
|
||||||
<a-space class="status-button">
|
<a-space class="status-button">
|
||||||
<a-button @click="setVisible(false)">关闭</a-button>
|
<a-button @click="setVisible(false)">关闭</a-button>
|
||||||
<a-button v-if="session.status.closeCode !== TerminalCloseCode.FORCE && session.status.canReconnect"
|
<a-button v-if="session.state.closeCode !== TerminalCloseCode.FORCE && session.state.canReconnect"
|
||||||
type="primary"
|
type="primary"
|
||||||
@click="reOpenSession(session.sessionKey)">
|
@click="reOpenSession(session.sessionKey)">
|
||||||
重连
|
重连
|
||||||
|
|||||||
@@ -45,7 +45,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- 已关闭-右侧操作 -->
|
<!-- 已关闭-右侧操作 -->
|
||||||
<div v-if="session?.status.connected === false && closeMessage !== undefined"
|
<div v-if="session?.state.connected === false && closeMessage !== undefined"
|
||||||
class="sftp-table-header-right">
|
class="sftp-table-header-right">
|
||||||
<!-- 错误信息 -->
|
<!-- 错误信息 -->
|
||||||
<a-tag class="close-message"
|
<a-tag class="close-message"
|
||||||
@@ -54,7 +54,7 @@
|
|||||||
已断开: {{ closeMessage }}
|
已断开: {{ closeMessage }}
|
||||||
</a-tag>
|
</a-tag>
|
||||||
<!-- 重连 -->
|
<!-- 重连 -->
|
||||||
<a-tooltip v-if="session?.status.connected === false && session?.status.canReconnect"
|
<a-tooltip v-if="session?.state.connected === false && session?.state.canReconnect"
|
||||||
position="top"
|
position="top"
|
||||||
:mini="true"
|
:mini="true"
|
||||||
:overlay-inverse="true"
|
:overlay-inverse="true"
|
||||||
@@ -245,7 +245,7 @@
|
|||||||
// 设置命令编辑模式
|
// 设置命令编辑模式
|
||||||
const setPathEditable = (editable: boolean) => {
|
const setPathEditable = (editable: boolean) => {
|
||||||
// 检查是否断开
|
// 检查是否断开
|
||||||
if (editable && !props.session?.status.connected) {
|
if (editable && !props.session?.state.connected) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
pathEditable.value = editable;
|
pathEditable.value = editable;
|
||||||
@@ -267,7 +267,7 @@
|
|||||||
// 加载文件列表
|
// 加载文件列表
|
||||||
const loadFileList = (path: string = props.currentPath) => {
|
const loadFileList = (path: string = props.currentPath) => {
|
||||||
// 检查是否断开
|
// 检查是否断开
|
||||||
if (!props.session?.status.connected) {
|
if (!props.session?.state.connected) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
emits('loadFile', path);
|
emits('loadFile', path);
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
row-key="path"
|
row-key="path"
|
||||||
ref="tableRef"
|
ref="tableRef"
|
||||||
class="sftp-table"
|
class="sftp-table"
|
||||||
:columns="columns"
|
:columns="sftpColumns"
|
||||||
:row-selection="rowSelection"
|
:row-selection="rowSelection"
|
||||||
:sticky-header="true"
|
:sticky-header="true"
|
||||||
:data="list"
|
:data="list"
|
||||||
@@ -149,7 +149,7 @@
|
|||||||
import { dateFormat } from '@/utils';
|
import { dateFormat } from '@/utils';
|
||||||
import { setAutoFocus } from '@/utils/dom';
|
import { setAutoFocus } from '@/utils/dom';
|
||||||
import { copy } from '@/hooks/copy';
|
import { copy } from '@/hooks/copy';
|
||||||
import columns from './types/table.columns';
|
import { sftpColumns } from '@/views/terminal/types/table.columns';
|
||||||
import { FILE_TYPE, openSftpChmodModalKey, openSftpMoveModalKey } from '@/views/terminal/types/const';
|
import { FILE_TYPE, openSftpChmodModalKey, openSftpMoveModalKey } from '@/views/terminal/types/const';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
@@ -205,7 +205,7 @@
|
|||||||
const clickFilename = (record: TableData) => {
|
const clickFilename = (record: TableData) => {
|
||||||
if (record.isDir) {
|
if (record.isDir) {
|
||||||
// 检查是否断开
|
// 检查是否断开
|
||||||
if (!props.session?.status.connected) {
|
if (!props.session?.state.connected) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// 进入文件夹
|
// 进入文件夹
|
||||||
@@ -218,7 +218,7 @@
|
|||||||
// 编辑文件
|
// 编辑文件
|
||||||
const editFile = (record: TableData) => {
|
const editFile = (record: TableData) => {
|
||||||
// 检查是否断开
|
// 检查是否断开
|
||||||
if (!props.session?.status.connected) {
|
if (!props.session?.state.connected) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
emits('editFile', record.name, record.path);
|
emits('editFile', record.name, record.path);
|
||||||
@@ -228,7 +228,7 @@
|
|||||||
// 删除文件
|
// 删除文件
|
||||||
const deleteFile = (path: string) => {
|
const deleteFile = (path: string) => {
|
||||||
// 检查是否断开
|
// 检查是否断开
|
||||||
if (!props.session?.status.connected) {
|
if (!props.session?.state.connected) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
emits('deleteFile', [path]);
|
emits('deleteFile', [path]);
|
||||||
@@ -237,7 +237,7 @@
|
|||||||
// 下载文件
|
// 下载文件
|
||||||
const downloadFile = (path: string) => {
|
const downloadFile = (path: string) => {
|
||||||
// 检查是否断开
|
// 检查是否断开
|
||||||
if (!props.session?.status.connected) {
|
if (!props.session?.state.connected) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
emits('download', [path], false);
|
emits('download', [path], false);
|
||||||
@@ -246,7 +246,7 @@
|
|||||||
// 移动文件
|
// 移动文件
|
||||||
const moveFile = (path: string) => {
|
const moveFile = (path: string) => {
|
||||||
// 检查是否断开
|
// 检查是否断开
|
||||||
if (!props.session?.status.connected) {
|
if (!props.session?.state.connected) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
openSftpMoveModal(props.session?.sessionKey as string, path);
|
openSftpMoveModal(props.session?.sessionKey as string, path);
|
||||||
@@ -255,7 +255,7 @@
|
|||||||
// 文件提权
|
// 文件提权
|
||||||
const chmodFile = (path: string, permission: number) => {
|
const chmodFile = (path: string, permission: number) => {
|
||||||
// 检查是否断开
|
// 检查是否断开
|
||||||
if (!props.session?.status.connected) {
|
if (!props.session?.state.connected) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
openSftpChmodModal(props.session?.sessionKey as string, path, permission);
|
openSftpChmodModal(props.session?.sessionKey as string, path, permission);
|
||||||
|
|||||||
@@ -23,8 +23,8 @@
|
|||||||
<!-- 连接状态 -->
|
<!-- 连接状态 -->
|
||||||
<a-badge v-if="preference.sshActionBarSetting.connectStatus !== false"
|
<a-badge v-if="preference.sshActionBarSetting.connectStatus !== false"
|
||||||
class="status-bridge"
|
class="status-bridge"
|
||||||
:status="getDictValue(connectStatusKey, session ? session.status.connectStatus : TerminalStatus.CONNECTING, 'status')"
|
:status="getDictValue(connectStatusKey, session ? session.state.connectStatus : TerminalStatus.CONNECTING, 'status')"
|
||||||
:text="getDictValue(connectStatusKey, session ? session.status.connectStatus : TerminalStatus.CONNECTING)" />
|
:text="getDictValue(connectStatusKey, session ? session.state.connectStatus : TerminalStatus.CONNECTING)" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ export interface SessionHostInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 会话状态
|
// 会话状态
|
||||||
export interface ReactiveSessionStatus {
|
export interface ReactiveSessionState {
|
||||||
// 连接状态
|
// 连接状态
|
||||||
connectStatus: number;
|
connectStatus: number;
|
||||||
// 是否已连接
|
// 是否已连接
|
||||||
@@ -54,7 +54,7 @@ export interface ReactiveSessionStatus {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// guacd 会话状态
|
// guacd 会话状态
|
||||||
export interface GuacdReactiveSessionStatus extends ReactiveSessionStatus {
|
export interface GuacdReactiveSessionStatus extends ReactiveSessionState {
|
||||||
// 关闭码
|
// 关闭码
|
||||||
closeCode: number;
|
closeCode: number;
|
||||||
// 关闭信息
|
// 关闭信息
|
||||||
@@ -76,7 +76,7 @@ export interface IDomViewportHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 终端会话定义
|
// 终端会话定义
|
||||||
export interface ITerminalSession<Status extends ReactiveSessionStatus = ReactiveSessionStatus> {
|
export interface ITerminalSession<State extends ReactiveSessionState = ReactiveSessionState> {
|
||||||
readonly type: string;
|
readonly type: string;
|
||||||
|
|
||||||
// 会话主机信息
|
// 会话主机信息
|
||||||
@@ -88,7 +88,7 @@ export interface ITerminalSession<Status extends ReactiveSessionStatus = Reactiv
|
|||||||
// 后端交互的唯一值 后端的 sessionId
|
// 后端交互的唯一值 后端的 sessionId
|
||||||
sessionId: string;
|
sessionId: string;
|
||||||
// 会话状态
|
// 会话状态
|
||||||
readonly status: Reactive<Status>;
|
readonly state: Reactive<State>;
|
||||||
|
|
||||||
// 重新初始化
|
// 重新初始化
|
||||||
reInit: () => Promise<void>;
|
reInit: () => Promise<void>;
|
||||||
|
|||||||
@@ -131,10 +131,10 @@ export default abstract class BaseGuacdChannel<T extends ITerminalSession<GuacdR
|
|||||||
this.onerror(new Guacamole.Status(closeCode as any, msg));
|
this.onerror(new Guacamole.Status(closeCode as any, msg));
|
||||||
}
|
}
|
||||||
// 设置关闭原因
|
// 设置关闭原因
|
||||||
this.session.status.closeCode = closeCode;
|
this.session.state.closeCode = closeCode;
|
||||||
this.session.status.closeMessage = msg || TerminalMessages.sessionClosed;
|
this.session.state.closeMessage = msg || TerminalMessages.sessionClosed;
|
||||||
// 设置重连状态
|
// 设置重连状态
|
||||||
this.session.status.canReconnect = TerminalCloseCode.FORCE !== closeCode;
|
this.session.state.canReconnect = TerminalCloseCode.FORCE !== closeCode;
|
||||||
// 设置已关闭
|
// 设置已关闭
|
||||||
this.setState(Guacamole.Tunnel.State.CLOSED);
|
this.setState(Guacamole.Tunnel.State.CLOSED);
|
||||||
this.session.setClosed();
|
this.session.setClosed();
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ export default class SftpChannel extends BaseTerminalChannel<ISftpSession> imple
|
|||||||
}
|
}
|
||||||
const codeNumber = Number.parseInt(code);
|
const codeNumber = Number.parseInt(code);
|
||||||
this.triggerClosed = true;
|
this.triggerClosed = true;
|
||||||
this.session.status.canReconnect = TerminalCloseCode.FORCE !== codeNumber;
|
this.session.state.canReconnect = TerminalCloseCode.FORCE !== codeNumber;
|
||||||
// 设置已关闭
|
// 设置已关闭
|
||||||
this.session.setClosed();
|
this.session.setClosed();
|
||||||
// sftp 设置状态
|
// sftp 设置状态
|
||||||
|
|||||||
@@ -36,13 +36,13 @@ export default class SshChannel extends BaseTerminalChannel<ISshSession> impleme
|
|||||||
if (this.triggerClosed) {
|
if (this.triggerClosed) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const beforeConnected = this.session.status.connected;
|
const beforeConnected = this.session.state.connected;
|
||||||
this.triggerClosed = true;
|
this.triggerClosed = true;
|
||||||
// 设置重连状态
|
// 设置重连状态
|
||||||
this.session.status.canReconnect = TerminalCloseCode.FORCE !== Number.parseInt(code);
|
this.session.state.canReconnect = TerminalCloseCode.FORCE !== Number.parseInt(code);
|
||||||
// 拼接关闭消息
|
// 拼接关闭消息
|
||||||
this.session.write((beforeConnected ? '\r\n\r\n' : '') + ansi(91, msg || ''));
|
this.session.write((beforeConnected ? '\r\n\r\n' : '') + ansi(91, msg || ''));
|
||||||
if (this.session.status.canReconnect) {
|
if (this.session.state.canReconnect) {
|
||||||
this.session.write('\r\n' + ansi(91, TerminalMessages.waitingReconnect) + '\r\n');
|
this.session.write('\r\n' + ansi(91, TerminalMessages.waitingReconnect) + '\r\n');
|
||||||
}
|
}
|
||||||
// 设置已关闭
|
// 设置已关闭
|
||||||
|
|||||||
@@ -82,9 +82,9 @@ export default class SshSessionHandler implements ISshSessionHandler {
|
|||||||
case 'openSftp':
|
case 'openSftp':
|
||||||
case 'uploadFile':
|
case 'uploadFile':
|
||||||
case 'checkAppendMissing':
|
case 'checkAppendMissing':
|
||||||
return this.session.status.canWrite;
|
return this.session.state.canWrite;
|
||||||
case 'disconnect':
|
case 'disconnect':
|
||||||
return this.session.status.connected;
|
return this.session.state.connected;
|
||||||
default:
|
default:
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -193,7 +193,7 @@ export default class SshSessionHandler implements ISshSessionHandler {
|
|||||||
// 字号增加
|
// 字号增加
|
||||||
private fontSizeAdd(addSize: number) {
|
private fontSizeAdd(addSize: number) {
|
||||||
this.inst.options['fontSize'] = this.inst.options['fontSize'] as number + addSize;
|
this.inst.options['fontSize'] = this.inst.options['fontSize'] as number + addSize;
|
||||||
if (this.session.status.connected) {
|
if (this.session.state.connected) {
|
||||||
this.session.fit();
|
this.session.fit();
|
||||||
this.inst.focus();
|
this.inst.focus();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,21 +1,21 @@
|
|||||||
import type { Reactive } from 'vue';
|
import type { Reactive } from 'vue';
|
||||||
import { reactive } from 'vue';
|
import { reactive } from 'vue';
|
||||||
import type { ITerminalChannel, ITerminalSession, ReactiveSessionStatus, SessionHostInfo, TerminalSessionTabItem } from '@/views/terminal/interfaces';
|
import type { ITerminalChannel, ITerminalSession, ReactiveSessionState, SessionHostInfo, TerminalSessionTabItem } from '@/views/terminal/interfaces';
|
||||||
import { TerminalStatus } from '@/views/terminal/types/const';
|
import { TerminalStatus } from '@/views/terminal/types/const';
|
||||||
|
|
||||||
// 会话基类
|
// 会话基类
|
||||||
export default abstract class BaseSession<Status extends ReactiveSessionStatus, Channel extends ITerminalChannel>
|
export default abstract class BaseSession<State extends ReactiveSessionState, Channel extends ITerminalChannel>
|
||||||
implements ITerminalSession<Status> {
|
implements ITerminalSession<State> {
|
||||||
|
|
||||||
public readonly type: string;
|
public readonly type: string;
|
||||||
public readonly info: SessionHostInfo;
|
public readonly info: SessionHostInfo;
|
||||||
public readonly panelIndex: number;
|
public readonly panelIndex: number;
|
||||||
public readonly status: Reactive<Status>;
|
public readonly state: Reactive<State>;
|
||||||
public readonly sessionKey: string;
|
public readonly sessionKey: string;
|
||||||
public sessionId: string;
|
public sessionId: string;
|
||||||
protected channel: Channel;
|
protected channel: Channel;
|
||||||
|
|
||||||
protected constructor(item: TerminalSessionTabItem, reactiveStatus: Partial<Status>) {
|
protected constructor(item: TerminalSessionTabItem, state: Partial<State>) {
|
||||||
this.type = item.type;
|
this.type = item.type;
|
||||||
this.info = {
|
this.info = {
|
||||||
hostId: item.hostId,
|
hostId: item.hostId,
|
||||||
@@ -26,13 +26,13 @@ export default abstract class BaseSession<Status extends ReactiveSessionStatus,
|
|||||||
this.panelIndex = item.panelIndex;
|
this.panelIndex = item.panelIndex;
|
||||||
this.sessionKey = item.key;
|
this.sessionKey = item.key;
|
||||||
this.sessionId = item.key;
|
this.sessionId = item.key;
|
||||||
this.status = reactive({
|
this.state = reactive({
|
||||||
connectStatus: TerminalStatus.CONNECTING,
|
connectStatus: TerminalStatus.CONNECTING,
|
||||||
connected: false,
|
connected: false,
|
||||||
canWrite: false,
|
canWrite: false,
|
||||||
canReconnect: false,
|
canReconnect: false,
|
||||||
...reactiveStatus,
|
...state,
|
||||||
} as Status);
|
} as State);
|
||||||
this.channel = undefined as unknown as Channel;
|
this.channel = undefined as unknown as Channel;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,28 +62,28 @@ export default abstract class BaseSession<Status extends ReactiveSessionStatus,
|
|||||||
|
|
||||||
// 设置是否可写
|
// 设置是否可写
|
||||||
setCanWrite(canWrite: boolean): void {
|
setCanWrite(canWrite: boolean): void {
|
||||||
this.status.canWrite = canWrite;
|
this.state.canWrite = canWrite;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 设置连接中
|
// 设置连接中
|
||||||
setConnecting(): void {
|
setConnecting(): void {
|
||||||
this.status.connected = false;
|
this.state.connected = false;
|
||||||
this.status.canWrite = false;
|
this.state.canWrite = false;
|
||||||
this.status.connectStatus = TerminalStatus.CONNECTING;
|
this.state.connectStatus = TerminalStatus.CONNECTING;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 设置已连接
|
// 设置已连接
|
||||||
setConnected(): void {
|
setConnected(): void {
|
||||||
// 设置状态
|
// 设置状态
|
||||||
this.status.connected = true;
|
this.state.connected = true;
|
||||||
this.status.connectStatus = TerminalStatus.CONNECTED;
|
this.state.connectStatus = TerminalStatus.CONNECTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 设置已关闭
|
// 设置已关闭
|
||||||
setClosed(): void {
|
setClosed(): void {
|
||||||
this.status.connected = false;
|
this.state.connected = false;
|
||||||
this.status.canWrite = false;
|
this.state.canWrite = false;
|
||||||
this.status.connectStatus = TerminalStatus.CLOSED;
|
this.state.connectStatus = TerminalStatus.CLOSED;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -128,7 +128,7 @@ export default class RdpSession extends BaseSession<GuacdReactiveSessionStatus,
|
|||||||
// 定时检查是否连接成功
|
// 定时检查是否连接成功
|
||||||
this.connectTimeoutId = window.setTimeout(() => {
|
this.connectTimeoutId = window.setTimeout(() => {
|
||||||
// 未连接上证明连接超时
|
// 未连接上证明连接超时
|
||||||
if (!this.status.connected) {
|
if (!this.state.connected) {
|
||||||
this.channel.closeTunnel(TerminalCloseCode.CONNECT_TIMEOUT, TerminalMessages.rdpConnectTimeout);
|
this.channel.closeTunnel(TerminalCloseCode.CONNECT_TIMEOUT, TerminalMessages.rdpConnectTimeout);
|
||||||
}
|
}
|
||||||
}, CONNECT_TIMEOUT);
|
}, CONNECT_TIMEOUT);
|
||||||
@@ -217,7 +217,7 @@ export default class RdpSession extends BaseSession<GuacdReactiveSessionStatus,
|
|||||||
|
|
||||||
// 是否可写
|
// 是否可写
|
||||||
isWriteable(): boolean {
|
isWriteable(): boolean {
|
||||||
return this.status.connected && this.status.canWrite;
|
return this.state.connected && this.state.canWrite;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 设置为已关闭
|
// 设置为已关闭
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { ISftpChannel, ISftpSession, ISftpSessionHandler, ReactiveSessionStatus, TerminalSessionTabItem } from '@/views/terminal/interfaces';
|
import type { ISftpChannel, ISftpSession, ISftpSessionHandler, ReactiveSessionState, TerminalSessionTabItem } from '@/views/terminal/interfaces';
|
||||||
import { h } from 'vue';
|
import { h } from 'vue';
|
||||||
import { InputProtocol } from '@/views/terminal/types/protocol';
|
import { InputProtocol } from '@/views/terminal/types/protocol';
|
||||||
import { Modal } from '@arco-design/web-vue';
|
import { Modal } from '@arco-design/web-vue';
|
||||||
@@ -6,7 +6,7 @@ import BaseSession from './base-session';
|
|||||||
import SftpChannel from '../channel/sftp-channel';
|
import SftpChannel from '../channel/sftp-channel';
|
||||||
|
|
||||||
// SFTP 会话实现
|
// SFTP 会话实现
|
||||||
export default class SftpSession extends BaseSession<ReactiveSessionStatus, ISftpChannel> implements ISftpSession {
|
export default class SftpSession extends BaseSession<ReactiveSessionState, ISftpChannel> implements ISftpSession {
|
||||||
|
|
||||||
public handler: ISftpSessionHandler;
|
public handler: ISftpSessionHandler;
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { ISshChannel, ISshSession, ISshSessionHandler, ReactiveSessionStatus, SshInitConfig, TerminalSessionTabItem } from '@/views/terminal/interfaces';
|
import type { ISshChannel, ISshSession, ISshSessionHandler, ReactiveSessionState, SshInitConfig, TerminalSessionTabItem } from '@/views/terminal/interfaces';
|
||||||
import type { UnwrapRef } from 'vue';
|
import type { UnwrapRef } from 'vue';
|
||||||
import type { ISearchOptions } from '@xterm/addon-search';
|
import type { ISearchOptions } from '@xterm/addon-search';
|
||||||
import { SearchAddon } from '@xterm/addon-search';
|
import { SearchAddon } from '@xterm/addon-search';
|
||||||
@@ -23,7 +23,7 @@ import SshChannel from '../channel/ssh-channel';
|
|||||||
import SshSessionHandler from '../handler/ssh-session-handler';
|
import SshSessionHandler from '../handler/ssh-session-handler';
|
||||||
|
|
||||||
// SSH 会话实现
|
// SSH 会话实现
|
||||||
export default class SshSession extends BaseSession<ReactiveSessionStatus, ISshChannel> implements ISshSession {
|
export default class SshSession extends BaseSession<ReactiveSessionState, ISshChannel> implements ISshSession {
|
||||||
|
|
||||||
public inst: Terminal;
|
public inst: Terminal;
|
||||||
|
|
||||||
@@ -102,9 +102,9 @@ export default class SshSession extends BaseSession<ReactiveSessionStatus, ISshC
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
}
|
}
|
||||||
// 检查重新连接
|
// 检查重新连接
|
||||||
if (!this.status.connected && this.status.canReconnect && e.key === 'Enter') {
|
if (!this.state.connected && this.state.canReconnect && e.key === 'Enter') {
|
||||||
// 防止重复回车
|
// 防止重复回车
|
||||||
this.status.canReconnect = false;
|
this.state.canReconnect = false;
|
||||||
// 异步作用域重新连接
|
// 异步作用域重新连接
|
||||||
setTimeout(async () => {
|
setTimeout(async () => {
|
||||||
await useTerminalStore().reOpenSession(this.sessionKey);
|
await useTerminalStore().reOpenSession(this.sessionKey);
|
||||||
@@ -129,7 +129,7 @@ export default class SshSession extends BaseSession<ReactiveSessionStatus, ISshC
|
|||||||
private registerEvent(dom: HTMLElement, preference: UnwrapRef<TerminalPreference>) {
|
private registerEvent(dom: HTMLElement, preference: UnwrapRef<TerminalPreference>) {
|
||||||
// 注册输入事件
|
// 注册输入事件
|
||||||
this.inst.onData(s => {
|
this.inst.onData(s => {
|
||||||
if (!this.status.canWrite || !this.status.connected) {
|
if (!this.state.canWrite || !this.state.connected) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// 输入
|
// 输入
|
||||||
@@ -153,7 +153,7 @@ export default class SshSession extends BaseSession<ReactiveSessionStatus, ISshC
|
|||||||
}
|
}
|
||||||
// 注册 resize 事件
|
// 注册 resize 事件
|
||||||
this.inst.onResize(({ cols, rows }) => {
|
this.inst.onResize(({ cols, rows }) => {
|
||||||
if (!this.status.connected) {
|
if (!this.state.connected) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.channel.send(InputProtocol.RESIZE, {
|
this.channel.send(InputProtocol.RESIZE, {
|
||||||
@@ -165,7 +165,7 @@ export default class SshSession extends BaseSession<ReactiveSessionStatus, ISshC
|
|||||||
addEventListen(dom, 'contextmenu', async () => {
|
addEventListen(dom, 'contextmenu', async () => {
|
||||||
// 右键粘贴逻辑
|
// 右键粘贴逻辑
|
||||||
if (preference.interactSetting.rightClickPaste) {
|
if (preference.interactSetting.rightClickPaste) {
|
||||||
if (!this.status.canWrite || !this.status.connected) {
|
if (!this.state.canWrite || !this.state.connected) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// 未开启右键选中 || 开启并无选中的内容则粘贴
|
// 未开启右键选中 || 开启并无选中的内容则粘贴
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ export default class RdpFileDownloadTask extends BaseFileTransferTask implements
|
|||||||
}
|
}
|
||||||
this.state.aborted = true;
|
this.state.aborted = true;
|
||||||
try {
|
try {
|
||||||
if (this.session.status.connected) {
|
if (this.session.state.connected) {
|
||||||
if (this.stream) {
|
if (this.stream) {
|
||||||
// 发送 ACK
|
// 发送 ACK
|
||||||
this.stream.sendAck('Aborted', Guacamole.Status.Code.RESOURCE_CLOSED);
|
this.stream.sendAck('Aborted', Guacamole.Status.Code.RESOURCE_CLOSED);
|
||||||
|
|||||||
@@ -117,7 +117,7 @@ export default class RdpFileUploadTask extends BaseFileTransferTask implements I
|
|||||||
}
|
}
|
||||||
this.state.aborted = true;
|
this.state.aborted = true;
|
||||||
try {
|
try {
|
||||||
if (this.session.status.connected) {
|
if (this.session.state.connected) {
|
||||||
// 关闭流
|
// 关闭流
|
||||||
if (this.stream) {
|
if (this.stream) {
|
||||||
this.stream.sendEnd();
|
this.stream.sendEnd();
|
||||||
|
|||||||
@@ -485,6 +485,12 @@ export const TransferReceiver = {
|
|||||||
ABORT: 'abort',
|
ABORT: 'abort',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 路径书签类型
|
||||||
|
export const PathBookmarkType = {
|
||||||
|
FILE: 'FILE',
|
||||||
|
DIR: 'DIR',
|
||||||
|
};
|
||||||
|
|
||||||
// 打开 extraModal key
|
// 打开 extraModal key
|
||||||
export const openExtraModalKey = Symbol();
|
export const openExtraModalKey = Symbol();
|
||||||
|
|
||||||
|
|||||||
44
orion-visor-ui/src/views/terminal/types/form.rules.ts
Normal file
44
orion-visor-ui/src/views/terminal/types/form.rules.ts
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
import type { FieldRule } from '@arco-design/web-vue';
|
||||||
|
|
||||||
|
// 代码片段规则
|
||||||
|
export const commandSnippetFormRules = {
|
||||||
|
groupId: [{
|
||||||
|
message: '请选择分组'
|
||||||
|
}],
|
||||||
|
name: [{
|
||||||
|
required: true,
|
||||||
|
message: '请输入名称'
|
||||||
|
}, {
|
||||||
|
maxLength: 64,
|
||||||
|
message: '名称长度不能大于64位'
|
||||||
|
}],
|
||||||
|
command: [{
|
||||||
|
required: true,
|
||||||
|
message: '请输入代码片段'
|
||||||
|
}],
|
||||||
|
} as Record<string, FieldRule | FieldRule[]>;
|
||||||
|
|
||||||
|
// 书签路径规则
|
||||||
|
export const bookmarkFormRules = {
|
||||||
|
groupId: [{
|
||||||
|
message: '请选择分组'
|
||||||
|
}],
|
||||||
|
name: [{
|
||||||
|
required: true,
|
||||||
|
message: '请输入名称'
|
||||||
|
}, {
|
||||||
|
maxLength: 64,
|
||||||
|
message: '名称长度不能大于64位'
|
||||||
|
}],
|
||||||
|
type: [{
|
||||||
|
required: true,
|
||||||
|
message: '请选择类型'
|
||||||
|
}],
|
||||||
|
path: [{
|
||||||
|
required: true,
|
||||||
|
message: '请输入路径'
|
||||||
|
}, {
|
||||||
|
maxLength: 1000,
|
||||||
|
message: '路径长度不能大于1000位'
|
||||||
|
}],
|
||||||
|
} as Record<string, FieldRule | FieldRule[]>;
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
import type { TableColumnData } from '@arco-design/web-vue';
|
import type { TableColumnData } from '@arco-design/web-vue';
|
||||||
import { getFileSize } from '@/utils/file';
|
import { getFileSize } from '@/utils/file';
|
||||||
|
|
||||||
// 表格列
|
// SFTP 表格列
|
||||||
const columns = [
|
export const sftpColumns = [
|
||||||
{
|
{
|
||||||
title: '名称',
|
title: '名称',
|
||||||
dataIndex: 'name',
|
dataIndex: 'name',
|
||||||
@@ -45,4 +45,4 @@ const columns = [
|
|||||||
},
|
},
|
||||||
] as TableColumnData[];
|
] as TableColumnData[];
|
||||||
|
|
||||||
export default columns;
|
export default sftpColumns;
|
||||||
Reference in New Issue
Block a user