✨ 路径标签.
This commit is contained in:
@@ -42,6 +42,10 @@ public class PathBookmarkDO extends BaseDO {
|
|||||||
@TableField("name")
|
@TableField("name")
|
||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
|
@Schema(description = "类型")
|
||||||
|
@TableField("type")
|
||||||
|
private String type;
|
||||||
|
|
||||||
@Schema(description = "路径")
|
@Schema(description = "路径")
|
||||||
@TableField("path")
|
@TableField("path")
|
||||||
private String path;
|
private String path;
|
||||||
|
|||||||
@@ -34,6 +34,9 @@ public class PathBookmarkCacheDTO implements LongCacheIdModel, Serializable {
|
|||||||
@Schema(description = "名称")
|
@Schema(description = "名称")
|
||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
|
@Schema(description = "类型")
|
||||||
|
private String type;
|
||||||
|
|
||||||
@Schema(description = "路径")
|
@Schema(description = "路径")
|
||||||
private String path;
|
private String path;
|
||||||
|
|
||||||
|
|||||||
@@ -34,6 +34,11 @@ public class PathBookmarkCreateRequest implements Serializable {
|
|||||||
@Schema(description = "名称")
|
@Schema(description = "名称")
|
||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
|
@NotBlank
|
||||||
|
@Size(max = 4)
|
||||||
|
@Schema(description = "类型")
|
||||||
|
private String type;
|
||||||
|
|
||||||
@NotBlank
|
@NotBlank
|
||||||
@Size(max = 1024)
|
@Size(max = 1024)
|
||||||
@Schema(description = "路径")
|
@Schema(description = "路径")
|
||||||
|
|||||||
@@ -39,6 +39,11 @@ public class PathBookmarkUpdateRequest implements Serializable {
|
|||||||
@Schema(description = "名称")
|
@Schema(description = "名称")
|
||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
|
@NotBlank
|
||||||
|
@Size(max = 4)
|
||||||
|
@Schema(description = "类型")
|
||||||
|
private String type;
|
||||||
|
|
||||||
@NotBlank
|
@NotBlank
|
||||||
@Size(max = 1024)
|
@Size(max = 1024)
|
||||||
@Schema(description = "路径")
|
@Schema(description = "路径")
|
||||||
|
|||||||
@@ -36,6 +36,9 @@ public class PathBookmarkVO implements Serializable {
|
|||||||
@Schema(description = "名称")
|
@Schema(description = "名称")
|
||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
|
@Schema(description = "类型")
|
||||||
|
private String type;
|
||||||
|
|
||||||
@Schema(description = "路径")
|
@Schema(description = "路径")
|
||||||
private String path;
|
private String path;
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
<result column="user_id" property="userId"/>
|
<result column="user_id" property="userId"/>
|
||||||
<result column="group_id" property="groupId"/>
|
<result column="group_id" property="groupId"/>
|
||||||
<result column="name" property="name"/>
|
<result column="name" property="name"/>
|
||||||
|
<result column="type" property="type"/>
|
||||||
<result column="path" property="path"/>
|
<result column="path" property="path"/>
|
||||||
<result column="create_time" property="createTime"/>
|
<result column="create_time" property="createTime"/>
|
||||||
<result column="update_time" property="updateTime"/>
|
<result column="update_time" property="updateTime"/>
|
||||||
@@ -18,7 +19,7 @@
|
|||||||
|
|
||||||
<!-- 通用查询结果列 -->
|
<!-- 通用查询结果列 -->
|
||||||
<sql id="Base_Column_List">
|
<sql id="Base_Column_List">
|
||||||
id, user_id, group_id, name, path, create_time, update_time, creator, updater, deleted
|
id, user_id, group_id, name, type, path, create_time, update_time, creator, updater, deleted
|
||||||
</sql>
|
</sql>
|
||||||
|
|
||||||
</mapper>
|
</mapper>
|
||||||
|
|||||||
@@ -36,4 +36,7 @@ public class DictValueQueryRequest extends PageRequest {
|
|||||||
@Schema(description = "配置描述")
|
@Schema(description = "配置描述")
|
||||||
private String label;
|
private String label;
|
||||||
|
|
||||||
|
@Schema(description = "额外参数")
|
||||||
|
private String extra;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -374,6 +374,7 @@ public class DictValueServiceImpl implements DictValueService {
|
|||||||
.like(DictValueDO::getKeyName, request.getKeyName())
|
.like(DictValueDO::getKeyName, request.getKeyName())
|
||||||
.like(DictValueDO::getValue, request.getValue())
|
.like(DictValueDO::getValue, request.getValue())
|
||||||
.like(DictValueDO::getLabel, request.getLabel())
|
.like(DictValueDO::getLabel, request.getLabel())
|
||||||
|
.like(DictValueDO::getExtra, request.getExtra())
|
||||||
.orderByDesc(DictValueDO::getId);
|
.orderByDesc(DictValueDO::getId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import axios from 'axios';
|
|||||||
export interface PathBookmarkCreateRequest {
|
export interface PathBookmarkCreateRequest {
|
||||||
groupId?: number;
|
groupId?: number;
|
||||||
name?: string;
|
name?: string;
|
||||||
|
type?: string;
|
||||||
path?: string;
|
path?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -24,6 +25,7 @@ export interface PathBookmarkQueryResponse extends PathBookmarkQueryResponseExtr
|
|||||||
id: number;
|
id: number;
|
||||||
groupId: number;
|
groupId: number;
|
||||||
name: string;
|
name: string;
|
||||||
|
type: string;
|
||||||
path: string;
|
path: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -34,14 +34,11 @@ export interface DictValueRollbackRequest {
|
|||||||
* 字典配置值查询请求
|
* 字典配置值查询请求
|
||||||
*/
|
*/
|
||||||
export interface DictValueQueryRequest extends Pagination {
|
export interface DictValueQueryRequest extends Pagination {
|
||||||
searchValue?: string;
|
|
||||||
id?: number;
|
|
||||||
keyId?: number;
|
keyId?: number;
|
||||||
keyName?: string;
|
keyName?: string;
|
||||||
value?: string;
|
value?: string;
|
||||||
label?: string;
|
label?: string;
|
||||||
extra?: string;
|
extra?: string;
|
||||||
sort?: number;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import type {
|
|||||||
TerminalShortcutSetting,
|
TerminalShortcutSetting,
|
||||||
TerminalState
|
TerminalState
|
||||||
} from './types';
|
} from './types';
|
||||||
import type { ISftpSession, ISshSession, PanelSessionTabType, TerminalPanelTabItem } from '@/views/host/terminal/types/terminal.type';
|
import type { ITerminalSession, PanelSessionTabType, TerminalPanelTabItem } from '@/views/host/terminal/types/terminal.type';
|
||||||
import type { AuthorizedHostQueryResponse } from '@/api/asset/asset-authorized-data';
|
import type { AuthorizedHostQueryResponse } from '@/api/asset/asset-authorized-data';
|
||||||
import { getCurrentAuthorizedHost } from '@/api/asset/asset-authorized-data';
|
import { getCurrentAuthorizedHost } from '@/api/asset/asset-authorized-data';
|
||||||
import type { HostQueryResponse } from '@/api/asset/host';
|
import type { HostQueryResponse } from '@/api/asset/host';
|
||||||
@@ -18,7 +18,7 @@ import { defineStore } from 'pinia';
|
|||||||
import { getPreference, updatePreference } from '@/api/user/preference';
|
import { getPreference, updatePreference } from '@/api/user/preference';
|
||||||
import { nextId } from '@/utils';
|
import { nextId } from '@/utils';
|
||||||
import { Message } from '@arco-design/web-vue';
|
import { Message } from '@arco-design/web-vue';
|
||||||
import { PanelSessionType, TerminalTabs } from '@/views/host/terminal/types/terminal.const';
|
import { TerminalTabs } from '@/views/host/terminal/types/terminal.const';
|
||||||
import TerminalTabManager from '@/views/host/terminal/handler/terminal-tab-manager';
|
import TerminalTabManager from '@/views/host/terminal/handler/terminal-tab-manager';
|
||||||
import TerminalSessionManager from '@/views/host/terminal/handler/terminal-session-manager';
|
import TerminalSessionManager from '@/views/host/terminal/handler/terminal-session-manager';
|
||||||
import TerminalPanelManager from '@/views/host/terminal/handler/terminal-panel-manager';
|
import TerminalPanelManager from '@/views/host/terminal/handler/terminal-panel-manager';
|
||||||
@@ -195,8 +195,30 @@ export default defineStore('terminal', {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// 检查当前是否为终端页面 并且获取当前 ssh 会话
|
// 获取当前会话类型
|
||||||
getAndCheckCurrentSshSession(tips: boolean = true) {
|
getCurrentSessionType(tips: boolean = false) {
|
||||||
|
// 获取当前 activeTab
|
||||||
|
const activeTab = this.tabManager.active;
|
||||||
|
if (activeTab !== TerminalTabs.TERMINAL_PANEL.key) {
|
||||||
|
if (tips) {
|
||||||
|
Message.warning('请切换到终端标签页');
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 获取面板会话
|
||||||
|
const type = this.panelManager
|
||||||
|
.getCurrentPanel()
|
||||||
|
.getCurrentTab()
|
||||||
|
?.type;
|
||||||
|
if (!type && tips) {
|
||||||
|
Message.warning(`请打开 ${type}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return type;
|
||||||
|
},
|
||||||
|
|
||||||
|
// 获取当前会话
|
||||||
|
getCurrentSession<T extends ITerminalSession>(type: string, tips: boolean = false) {
|
||||||
// 获取当前 activeTab
|
// 获取当前 activeTab
|
||||||
const activeTab = this.tabManager.active;
|
const activeTab = this.tabManager.active;
|
||||||
if (activeTab !== TerminalTabs.TERMINAL_PANEL.key) {
|
if (activeTab !== TerminalTabs.TERMINAL_PANEL.key) {
|
||||||
@@ -206,37 +228,24 @@ export default defineStore('terminal', {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// 获取当前会话
|
// 获取当前会话
|
||||||
const session = this.getCurrentSshSession();
|
const session = this._getCurrentSession<T>(type);
|
||||||
if (!session && tips) {
|
if (!session && tips) {
|
||||||
Message.warning('请打开终端');
|
Message.warning(`请打开 ${type}`);
|
||||||
}
|
}
|
||||||
return session;
|
return session;
|
||||||
},
|
},
|
||||||
|
|
||||||
// 获取当前 ssh 会话
|
// 获取当前会话
|
||||||
getCurrentSshSession() {
|
_getCurrentSession<T extends ITerminalSession>(type: string): T | undefined {
|
||||||
// 获取面板会话
|
// 获取面板会话
|
||||||
const sessionTab = this.panelManager
|
const sessionTab = this.panelManager
|
||||||
.getCurrentPanel()
|
.getCurrentPanel()
|
||||||
.getCurrentTab();
|
.getCurrentTab();
|
||||||
if (!sessionTab || sessionTab.type !== PanelSessionType.SSH.type) {
|
if (!sessionTab || sessionTab.type !== type) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// 获取会话
|
// 获取会话
|
||||||
return this.sessionManager.getSession<ISshSession>(sessionTab.sessionId);
|
return this.sessionManager.getSession<T>(sessionTab.sessionId);
|
||||||
},
|
|
||||||
|
|
||||||
// 获取当前 sftp 会话
|
|
||||||
getCurrentSftpSession() {
|
|
||||||
// 获取面板会话
|
|
||||||
const sessionTab = this.panelManager
|
|
||||||
.getCurrentPanel()
|
|
||||||
.getCurrentTab();
|
|
||||||
if (!sessionTab || sessionTab.type !== PanelSessionType.SFTP.type) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// 获取会话
|
|
||||||
return this.sessionManager.getSession<ISftpSession>(sessionTab.sessionId);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -114,6 +114,12 @@
|
|||||||
{{ record.hostAddress }}
|
{{ record.hostAddress }}
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
|
<!-- 类型 -->
|
||||||
|
<template #type="{ record }">
|
||||||
|
<a-tag :color="getDictValue(connectTypeKey, record.type, 'color')">
|
||||||
|
{{ getDictValue(connectTypeKey, record.type) }}
|
||||||
|
</a-tag>
|
||||||
|
</template>
|
||||||
<!-- 状态 -->
|
<!-- 状态 -->
|
||||||
<template #status="{ record }">
|
<template #status="{ record }">
|
||||||
<span class="circle" :style="{
|
<span class="circle" :style="{
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ const columns = [
|
|||||||
title: '状态',
|
title: '状态',
|
||||||
dataIndex: 'status',
|
dataIndex: 'status',
|
||||||
slotName: 'status',
|
slotName: 'status',
|
||||||
align: 'left',
|
align: 'center',
|
||||||
width: 106,
|
width: 106,
|
||||||
}, {
|
}, {
|
||||||
title: '留痕地址',
|
title: '留痕地址',
|
||||||
|
|||||||
@@ -78,6 +78,7 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import type { ISshSession } from '@/views/host/terminal/types/terminal.type';
|
||||||
import type { CommandSnippetWrapperResponse, CommandSnippetQueryResponse } from '@/api/asset/command-snippet';
|
import type { CommandSnippetWrapperResponse, CommandSnippetQueryResponse } from '@/api/asset/command-snippet';
|
||||||
import { ref, provide } from 'vue';
|
import { ref, provide } from 'vue';
|
||||||
import useVisible from '@/hooks/visible';
|
import useVisible from '@/hooks/visible';
|
||||||
@@ -85,13 +86,14 @@
|
|||||||
import { deleteCommandSnippet, getCommandSnippetList } from '@/api/asset/command-snippet';
|
import { deleteCommandSnippet, getCommandSnippetList } from '@/api/asset/command-snippet';
|
||||||
import { useCacheStore, useTerminalStore } from '@/store';
|
import { useCacheStore, useTerminalStore } from '@/store';
|
||||||
import { openUpdateSnippetKey, removeSnippetKey } from '../types/const';
|
import { openUpdateSnippetKey, removeSnippetKey } from '../types/const';
|
||||||
|
import { PanelSessionType } from '@/views/host/terminal/types/terminal.const';
|
||||||
import CommandSnippetListItem from './command-snippet-list-item.vue';
|
import CommandSnippetListItem from './command-snippet-list-item.vue';
|
||||||
import CommandSnippetListGroup from './command-snippet-list-group.vue';
|
import CommandSnippetListGroup from './command-snippet-list-group.vue';
|
||||||
import CommandSnippetFormDrawer from './command-snippet-form-drawer.vue';
|
import CommandSnippetFormDrawer from './command-snippet-form-drawer.vue';
|
||||||
|
|
||||||
const { loading, setLoading } = useLoading();
|
const { loading, setLoading } = useLoading();
|
||||||
const { visible, setVisible } = useVisible();
|
const { visible, setVisible } = useVisible();
|
||||||
const { getCurrentSshSession } = useTerminalStore();
|
const { getCurrentSession } = useTerminalStore();
|
||||||
const cacheStore = useCacheStore();
|
const cacheStore = useCacheStore();
|
||||||
|
|
||||||
const formDrawer = ref();
|
const formDrawer = ref();
|
||||||
@@ -274,8 +276,8 @@
|
|||||||
|
|
||||||
// 关闭回调
|
// 关闭回调
|
||||||
const onClose = () => {
|
const onClose = () => {
|
||||||
// 聚焦终端
|
// 关闭时候如果打开的是终端 则聚焦终端
|
||||||
getCurrentSshSession()?.focus();
|
getCurrentSession<ISshSession>(PanelSessionType.SSH.type)?.focus();
|
||||||
};
|
};
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -113,18 +113,20 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import type { ISshSession } from '@/views/host/terminal/types/terminal.type';
|
||||||
import type { CommandSnippetQueryResponse } from '@/api/asset/command-snippet';
|
import type { CommandSnippetQueryResponse } from '@/api/asset/command-snippet';
|
||||||
import { useTerminalStore } from '@/store';
|
import { useTerminalStore } from '@/store';
|
||||||
import { useDebounceFn } from '@vueuse/core';
|
import { useDebounceFn } from '@vueuse/core';
|
||||||
import { copy } from '@/hooks/copy';
|
import { copy } from '@/hooks/copy';
|
||||||
import { inject } from 'vue';
|
import { inject } from 'vue';
|
||||||
import { openUpdateSnippetKey, removeSnippetKey } from '../types/const';
|
import { openUpdateSnippetKey, removeSnippetKey } from '../types/const';
|
||||||
|
import { PanelSessionType } from '@/views/host/terminal/types/terminal.const';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
item: CommandSnippetQueryResponse;
|
item: CommandSnippetQueryResponse;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const { getAndCheckCurrentSshSession } = useTerminalStore();
|
const { getCurrentSession } = useTerminalStore();
|
||||||
|
|
||||||
let clickCount = 0;
|
let clickCount = 0;
|
||||||
|
|
||||||
@@ -137,9 +139,11 @@
|
|||||||
// 点击命令
|
// 点击命令
|
||||||
const clickItem = () => {
|
const clickItem = () => {
|
||||||
if (++clickCount == 2) {
|
if (++clickCount == 2) {
|
||||||
|
// 双击执行
|
||||||
clickCount = 0;
|
clickCount = 0;
|
||||||
exec();
|
exec();
|
||||||
} else {
|
} else {
|
||||||
|
// 单击展开
|
||||||
expandItem();
|
expandItem();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -183,7 +187,7 @@
|
|||||||
|
|
||||||
// 写入命令
|
// 写入命令
|
||||||
const write = (command: string) => {
|
const write = (command: string) => {
|
||||||
const handler = getAndCheckCurrentSshSession()?.handler;
|
const handler = getCurrentSession<ISshSession>(PanelSessionType.SSH.type, true)?.handler;
|
||||||
if (handler && handler.enabledStatus('checkAppendMissing')) {
|
if (handler && handler.enabledStatus('checkAppendMissing')) {
|
||||||
handler.checkAppendMissing(command);
|
handler.checkAppendMissing(command);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,13 @@
|
|||||||
<a-form-item field="groupId" label="分组">
|
<a-form-item field="groupId" label="分组">
|
||||||
<path-bookmark-group-select v-model="formModel.groupId" />
|
<path-bookmark-group-select v-model="formModel.groupId" />
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
|
<!-- 类型 -->
|
||||||
|
<a-form-item field="type" label="类型">
|
||||||
|
<a-select v-model="formModel.type"
|
||||||
|
:options="toOptions(pathBookmarkTypeKey)"
|
||||||
|
placeholder="请选择类型"
|
||||||
|
allow-clear />
|
||||||
|
</a-form-item>
|
||||||
<!-- 文件路径 -->
|
<!-- 文件路径 -->
|
||||||
<a-form-item field="path" label="路径">
|
<a-form-item field="path" label="路径">
|
||||||
<a-textarea v-model="formModel.path"
|
<a-textarea v-model="formModel.path"
|
||||||
@@ -49,11 +56,14 @@
|
|||||||
import useVisible from '@/hooks/visible';
|
import useVisible from '@/hooks/visible';
|
||||||
import { createPathBookmark, updatePathBookmark } from '@/api/asset/path-bookmark';
|
import { createPathBookmark, updatePathBookmark } from '@/api/asset/path-bookmark';
|
||||||
import formRules from '../types/form.rules';
|
import formRules from '../types/form.rules';
|
||||||
|
import { PathBookmarkType, pathBookmarkTypeKey } from '../types/const';
|
||||||
|
import { useDictStore } from '@/store';
|
||||||
import { Message } from '@arco-design/web-vue';
|
import { Message } from '@arco-design/web-vue';
|
||||||
import PathBookmarkGroupSelect from './path-bookmark-group-select.vue';
|
import PathBookmarkGroupSelect from './path-bookmark-group-select.vue';
|
||||||
|
|
||||||
const { visible, setVisible } = useVisible();
|
const { visible, setVisible } = useVisible();
|
||||||
const { loading, setLoading } = useLoading();
|
const { loading, setLoading } = useLoading();
|
||||||
|
const { toOptions } = useDictStore();
|
||||||
|
|
||||||
const title = ref<string>();
|
const title = ref<string>();
|
||||||
const isAddHandle = ref<boolean>(true);
|
const isAddHandle = ref<boolean>(true);
|
||||||
@@ -63,6 +73,7 @@
|
|||||||
id: undefined,
|
id: undefined,
|
||||||
groupId: undefined,
|
groupId: undefined,
|
||||||
name: undefined,
|
name: undefined,
|
||||||
|
type: PathBookmarkType.DIR,
|
||||||
path: undefined,
|
path: undefined,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -78,20 +78,22 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import { ISshSession } from '@/views/host/terminal/types/terminal.type';
|
||||||
import type { PathBookmarkWrapperResponse, PathBookmarkQueryResponse } from '@/api/asset/path-bookmark';
|
import type { PathBookmarkWrapperResponse, PathBookmarkQueryResponse } from '@/api/asset/path-bookmark';
|
||||||
import { ref, provide } from 'vue';
|
import { ref, provide, onMounted } from 'vue';
|
||||||
import useVisible from '@/hooks/visible';
|
import useVisible from '@/hooks/visible';
|
||||||
import useLoading from '@/hooks/loading';
|
import useLoading from '@/hooks/loading';
|
||||||
import { deletePathBookmark, getPathBookmarkList } from '@/api/asset/path-bookmark';
|
import { deletePathBookmark, getPathBookmarkList } from '@/api/asset/path-bookmark';
|
||||||
import { useCacheStore, useTerminalStore } from '@/store';
|
import { useCacheStore, useDictStore, useTerminalStore } from '@/store';
|
||||||
import { openUpdatePathKey, removePathKey } from '../types/const';
|
import { PanelSessionType } from '@/views/host/terminal/types/terminal.const';
|
||||||
|
import { dictKeys, openUpdatePathKey, removePathKey } from '../types/const';
|
||||||
import PathBookmarkListItem from './path-bookmark-list-item.vue';
|
import PathBookmarkListItem from './path-bookmark-list-item.vue';
|
||||||
import PathBookmarkListGroup from './path-bookmark-list-group.vue';
|
import PathBookmarkListGroup from './path-bookmark-list-group.vue';
|
||||||
import PathBookmarkFormDrawer from './path-bookmark-form-drawer.vue';
|
import PathBookmarkFormDrawer from './path-bookmark-form-drawer.vue';
|
||||||
|
|
||||||
const { loading, setLoading } = useLoading();
|
const { loading, setLoading } = useLoading();
|
||||||
const { visible, setVisible } = useVisible();
|
const { visible, setVisible } = useVisible();
|
||||||
const { getCurrentSshSession } = useTerminalStore();
|
const { getCurrentSession } = useTerminalStore();
|
||||||
const cacheStore = useCacheStore();
|
const cacheStore = useCacheStore();
|
||||||
|
|
||||||
const formDrawer = ref();
|
const formDrawer = ref();
|
||||||
@@ -274,10 +276,15 @@
|
|||||||
|
|
||||||
// 关闭回调
|
// 关闭回调
|
||||||
const onClose = () => {
|
const onClose = () => {
|
||||||
// 聚焦终端
|
// 关闭时候如果打开的是终端 则聚焦终端
|
||||||
getCurrentSshSession()?.focus();
|
getCurrentSession<ISshSession>(PanelSessionType.SSH.type)?.focus();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 加载字典值
|
||||||
|
onMounted(() => {
|
||||||
|
useDictStore().loadKeys(dictKeys);
|
||||||
|
});
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
|
|||||||
@@ -28,16 +28,16 @@
|
|||||||
</template>
|
</template>
|
||||||
进入
|
进入
|
||||||
</a-tag>
|
</a-tag>
|
||||||
<!-- 粘贴 -->
|
<!-- 复制 -->
|
||||||
<a-tag class="pointer usn"
|
<a-tag class="pointer usn"
|
||||||
size="small"
|
size="small"
|
||||||
:checkable="true"
|
:checkable="true"
|
||||||
:checked="true"
|
:checked="true"
|
||||||
@click.stop.prevent="paste">
|
@click.stop.prevent="copyPath">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<icon-paste />
|
<icon-copy />
|
||||||
</template>
|
</template>
|
||||||
粘贴
|
复制
|
||||||
</a-tag>
|
</a-tag>
|
||||||
</a-space>
|
</a-space>
|
||||||
</div>
|
</div>
|
||||||
@@ -50,12 +50,12 @@
|
|||||||
</div>
|
</div>
|
||||||
<!-- 右键菜单 -->
|
<!-- 右键菜单 -->
|
||||||
<template #content>
|
<template #content>
|
||||||
<!-- 进入父目录 -->
|
<!-- 进入 -->
|
||||||
<a-doption @click="changePath">
|
<a-doption @click="changePath">
|
||||||
<div class="terminal-context-menu-icon">
|
<div class="terminal-context-menu-icon">
|
||||||
<icon-link />
|
<icon-link />
|
||||||
</div>
|
</div>
|
||||||
<div>进入父目录</div>
|
<div>进入</div>
|
||||||
</a-doption>
|
</a-doption>
|
||||||
<!-- 复制 -->
|
<!-- 复制 -->
|
||||||
<a-doption @click="copyPath">
|
<a-doption @click="copyPath">
|
||||||
@@ -112,19 +112,21 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import type { ISftpSession, ISshSession } from '@/views/host/terminal/types/terminal.type';
|
||||||
import type { PathBookmarkQueryResponse } from '@/api/asset/path-bookmark';
|
import type { PathBookmarkQueryResponse } from '@/api/asset/path-bookmark';
|
||||||
import { useTerminalStore } from '@/store';
|
import { useTerminalStore } from '@/store';
|
||||||
import { useDebounceFn } from '@vueuse/core';
|
import { useDebounceFn } from '@vueuse/core';
|
||||||
import { copy } from '@/hooks/copy';
|
import { copy } from '@/hooks/copy';
|
||||||
import { inject } from 'vue';
|
import { inject } from 'vue';
|
||||||
import { openUpdatePathKey, removePathKey } from '../types/const';
|
|
||||||
import { getParentPath } from '@/utils/file';
|
import { getParentPath } from '@/utils/file';
|
||||||
|
import { openUpdatePathKey, PathBookmarkType, removePathKey } from '../types/const';
|
||||||
|
import { PanelSessionType } from '@/views/host/terminal/types/terminal.const';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
item: PathBookmarkQueryResponse;
|
item: PathBookmarkQueryResponse;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const { getAndCheckCurrentSshSession } = useTerminalStore();
|
const { getCurrentSession, getCurrentSessionType } = useTerminalStore();
|
||||||
|
|
||||||
let clickCount = 0;
|
let clickCount = 0;
|
||||||
|
|
||||||
@@ -138,8 +140,17 @@
|
|||||||
const clickItem = () => {
|
const clickItem = () => {
|
||||||
if (++clickCount == 2) {
|
if (++clickCount == 2) {
|
||||||
clickCount = 0;
|
clickCount = 0;
|
||||||
changePath();
|
// 双击
|
||||||
|
const type = getCurrentSessionType(true);
|
||||||
|
if (type === PanelSessionType.SSH.type) {
|
||||||
|
// SSH 粘贴
|
||||||
|
paste();
|
||||||
|
} else if (type === PanelSessionType.SFTP.type) {
|
||||||
|
// SFTP 切换目录
|
||||||
|
listFiles();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
|
// 单击展开
|
||||||
expandItem();
|
expandItem();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -173,18 +184,37 @@
|
|||||||
|
|
||||||
// 粘贴
|
// 粘贴
|
||||||
const paste = () => {
|
const paste = () => {
|
||||||
write(props.item.path);
|
writeCommand(props.item.path);
|
||||||
};
|
};
|
||||||
|
|
||||||
// 进入父目录
|
// 切换目录
|
||||||
const changePath = () => {
|
const changePath = () => {
|
||||||
const parentPath = getParentPath(props.item.path);
|
const type = getCurrentSessionType(true);
|
||||||
write( parentPath+ '\r\n');
|
if (type === PanelSessionType.SSH.type) {
|
||||||
|
const path = props.item.type === PathBookmarkType.DIR
|
||||||
|
? props.item.path
|
||||||
|
: getParentPath(props.item.path);
|
||||||
|
// SSH cd
|
||||||
|
writeCommand('cd ' + path + '\r\n');
|
||||||
|
} else if (type === PanelSessionType.SFTP.type) {
|
||||||
|
// SFTP 切换目录
|
||||||
|
listFiles();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 写入路径
|
// 查询 sftp 文件列表
|
||||||
const write = (command: string) => {
|
const listFiles = () => {
|
||||||
const handler = getAndCheckCurrentSshSession()?.handler;
|
// 如果非文件夹则查询父文件夹
|
||||||
|
const path = props.item.type === PathBookmarkType.DIR
|
||||||
|
? props.item.path
|
||||||
|
: getParentPath(props.item.path);
|
||||||
|
// 查询列表
|
||||||
|
getCurrentSession<ISftpSession>(PanelSessionType.SFTP.type, true)?.list(path);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 写入 ssh 命令
|
||||||
|
const writeCommand = (command: string) => {
|
||||||
|
const handler = getCurrentSession<ISshSession>(PanelSessionType.SSH.type, true)?.handler;
|
||||||
if (handler && handler.enabledStatus('checkAppendMissing')) {
|
if (handler && handler.enabledStatus('checkAppendMissing')) {
|
||||||
handler.checkAppendMissing(command);
|
handler.checkAppendMissing(command);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,17 @@
|
|||||||
|
// 路径书签类型
|
||||||
|
export const PathBookmarkType = {
|
||||||
|
FILE: 'FILE',
|
||||||
|
DIR: 'DIR',
|
||||||
|
};
|
||||||
|
|
||||||
// 打开 updatePath key
|
// 打开 updatePath key
|
||||||
export const openUpdatePathKey = Symbol();
|
export const openUpdatePathKey = Symbol();
|
||||||
|
|
||||||
// 删除 path key
|
// 删除 path key
|
||||||
export const removePathKey = Symbol();
|
export const removePathKey = Symbol();
|
||||||
|
|
||||||
|
// 路径书签类型 字典项
|
||||||
|
export const pathBookmarkTypeKey = 'pathBookmarkType';
|
||||||
|
|
||||||
|
// 加载的字典值
|
||||||
|
export const dictKeys = [pathBookmarkTypeKey];
|
||||||
|
|||||||
@@ -12,13 +12,22 @@ export const name = [{
|
|||||||
message: '名称长度不能大于64位'
|
message: '名称长度不能大于64位'
|
||||||
}] as FieldRule[];
|
}] as FieldRule[];
|
||||||
|
|
||||||
|
export const type = [{
|
||||||
|
required: true,
|
||||||
|
message: '请选择类型'
|
||||||
|
}] as FieldRule[];
|
||||||
|
|
||||||
export const path = [{
|
export const path = [{
|
||||||
required: true,
|
required: true,
|
||||||
message: '请输入路径'
|
message: '请输入路径'
|
||||||
|
}, {
|
||||||
|
maxLength: 1000,
|
||||||
|
message: '名称长度不能大于1000位'
|
||||||
}] as FieldRule[];
|
}] as FieldRule[];
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
groupId,
|
groupId,
|
||||||
name,
|
name,
|
||||||
|
type,
|
||||||
path,
|
path,
|
||||||
} as Record<string, FieldRule | FieldRule[]>;
|
} as Record<string, FieldRule | FieldRule[]>;
|
||||||
|
|||||||
@@ -33,7 +33,8 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { TerminalTabs, TerminalShortcutKeys } from '../../types/terminal.const';
|
import type { ISshSession } from '../../types/terminal.type';
|
||||||
|
import { TerminalTabs, TerminalShortcutKeys, PanelSessionType } from '../../types/terminal.const';
|
||||||
import { useTerminalStore } from '@/store';
|
import { useTerminalStore } from '@/store';
|
||||||
import { onMounted, onUnmounted, watch } from 'vue';
|
import { onMounted, onUnmounted, watch } from 'vue';
|
||||||
import { addEventListen, removeEventListen } from '@/utils/event';
|
import { addEventListen, removeEventListen } from '@/utils/event';
|
||||||
@@ -45,17 +46,17 @@
|
|||||||
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, getCurrentSshSession } = useTerminalStore();
|
const { preference, tabManager, getCurrentSession } = useTerminalStore();
|
||||||
|
|
||||||
// 监听 tab 切换
|
// 监听 tab 切换
|
||||||
watch(() => tabManager.active, (active, before) => {
|
watch(() => tabManager.active, (active, before) => {
|
||||||
// 失焦 tab
|
// 失焦 tab
|
||||||
if (before === TerminalTabs.TERMINAL_PANEL.key) {
|
if (before === TerminalTabs.TERMINAL_PANEL.key) {
|
||||||
getCurrentSshSession()?.blur();
|
getCurrentSession<ISshSession>(PanelSessionType.SSH.type)?.blur();
|
||||||
}
|
}
|
||||||
// 聚焦 tab
|
// 聚焦 tab
|
||||||
if (active === TerminalTabs.TERMINAL_PANEL.key) {
|
if (active === TerminalTabs.TERMINAL_PANEL.key) {
|
||||||
getCurrentSshSession()?.focus();
|
getCurrentSession<ISshSession>(PanelSessionType.SSH.type)?.focus();
|
||||||
}
|
}
|
||||||
// 修改标题
|
// 修改标题
|
||||||
document.title = Object.values(TerminalTabs)
|
document.title = Object.values(TerminalTabs)
|
||||||
|
|||||||
@@ -24,15 +24,16 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import type { SidebarAction } from '../../types/terminal.type';
|
import type { ISshSession, SidebarAction } from '../../types/terminal.type';
|
||||||
import { useTerminalStore } from '@/store';
|
import { useTerminalStore } from '@/store';
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
|
import { PanelSessionType } from '../../types/terminal.const';
|
||||||
import IconActions from './icon-actions.vue';
|
import IconActions from './icon-actions.vue';
|
||||||
import CommandSnippetListDrawer from '../../../command-snippet/components/command-snippet-list-drawer.vue';
|
import CommandSnippetListDrawer from '@/views/host/command-snippet/components/command-snippet-list-drawer.vue';
|
||||||
import PathBookmarkListDrawer from '../../../path-bookmark/components/path-bookmark-list-drawer.vue';
|
import PathBookmarkListDrawer from '@/views/host/path-bookmark/components/path-bookmark-list-drawer.vue';
|
||||||
import TransferDrawer from '@/views/host/terminal/components/transfer/transfer-drawer.vue';
|
import TransferDrawer from '@/views/host/terminal/components/transfer/transfer-drawer.vue';
|
||||||
|
|
||||||
const { getAndCheckCurrentSshSession } = useTerminalStore();
|
const { getCurrentSession } = useTerminalStore();
|
||||||
|
|
||||||
const snippetRef = ref();
|
const snippetRef = ref();
|
||||||
const pathRef = ref();
|
const pathRef = ref();
|
||||||
@@ -69,7 +70,7 @@
|
|||||||
|
|
||||||
// 终端截屏
|
// 终端截屏
|
||||||
const screenshot = () => {
|
const screenshot = () => {
|
||||||
const handler = getAndCheckCurrentSshSession()?.handler;
|
const handler = getCurrentSession<ISshSession>(PanelSessionType.SSH.type, true)?.handler;
|
||||||
if (handler && handler.enabledStatus('screenshot')) {
|
if (handler && handler.enabledStatus('screenshot')) {
|
||||||
handler.screenshot();
|
handler.screenshot();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -173,7 +173,6 @@
|
|||||||
|
|
||||||
// 加载文件列表
|
// 加载文件列表
|
||||||
const loadFiles = (path: string) => {
|
const loadFiles = (path: string) => {
|
||||||
setTableLoading(true);
|
|
||||||
session.value?.list(path);
|
session.value?.list(path);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ export default class SftpSession implements ISftpSession {
|
|||||||
|
|
||||||
// 查询文件列表
|
// 查询文件列表
|
||||||
list(path: string) {
|
list(path: string) {
|
||||||
|
this.resolver.setLoading(true);
|
||||||
this.channel.send(InputProtocol.SFTP_LIST, {
|
this.channel.send(InputProtocol.SFTP_LIST, {
|
||||||
sessionId: this.sessionId,
|
sessionId: this.sessionId,
|
||||||
showHiddenFile: ~~this.showHiddenFile,
|
showHiddenFile: ~~this.showHiddenFile,
|
||||||
|
|||||||
@@ -13,13 +13,17 @@
|
|||||||
allow-create
|
allow-create
|
||||||
allow-clear />
|
allow-clear />
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
|
<!-- 配置描述 -->
|
||||||
|
<a-form-item field="label" label="配置描述">
|
||||||
|
<a-input v-model="formModel.label" placeholder="请输入配置描述" allow-clear />
|
||||||
|
</a-form-item>
|
||||||
<!-- 配置值 -->
|
<!-- 配置值 -->
|
||||||
<a-form-item field="value" label="配置值">
|
<a-form-item field="value" label="配置值">
|
||||||
<a-input v-model="formModel.value" placeholder="请输入配置值" allow-clear />
|
<a-input v-model="formModel.value" placeholder="请输入配置值" allow-clear />
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<!-- 配置描述 -->
|
<!-- 配置值 -->
|
||||||
<a-form-item field="label" label="配置描述">
|
<a-form-item field="extra" label="额外参数">
|
||||||
<a-input v-model="formModel.label" placeholder="请输入配置描述" allow-clear />
|
<a-input v-model="formModel.extra" placeholder="额外参数" allow-clear />
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</query-header>
|
</query-header>
|
||||||
</a-card>
|
</a-card>
|
||||||
|
|||||||
Reference in New Issue
Block a user