feat: 查询命令分组.
This commit is contained in:
@@ -29,7 +29,7 @@ export interface CommandSnippetQueryResponse extends CommandSnippetQueryResponse
|
|||||||
|
|
||||||
export interface CommandSnippetQueryResponseExtra {
|
export interface CommandSnippetQueryResponseExtra {
|
||||||
visible: boolean;
|
visible: boolean;
|
||||||
expand: boolean;
|
expand?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -74,10 +74,10 @@
|
|||||||
</template>
|
</template>
|
||||||
</a-tree>
|
</a-tree>
|
||||||
<!-- 无数据 -->
|
<!-- 无数据 -->
|
||||||
<div v-else-if="!loading" class="empty-container">
|
<a-empty v-else-if="!loading" class="empty-container">
|
||||||
<span>暂无数据</span>
|
<span>暂无数据</span><br>
|
||||||
<span v-if="editable">点击上方 '<icon-plus />' 添加一个分组吧~</span>
|
<span v-if="editable">点击上方 '<icon-plus />' 添加一个分组吧~</span>
|
||||||
</div>
|
</a-empty>
|
||||||
</a-scrollbar>
|
</a-scrollbar>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -214,8 +214,8 @@
|
|||||||
|
|
||||||
// 保存节点
|
// 保存节点
|
||||||
const saveNode = async (node: TreeNodeData) => {
|
const saveNode = async (node: TreeNodeData) => {
|
||||||
const key = node.key
|
const key = node.key;
|
||||||
const newTitle = node.title
|
const newTitle = node.title;
|
||||||
node.modCount = (node.modCount || 0) + 1;
|
node.modCount = (node.modCount || 0) + 1;
|
||||||
if (node.modCount != 1) {
|
if (node.modCount != 1) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -159,7 +159,20 @@ export default defineStore('terminal', {
|
|||||||
if (host) {
|
if (host) {
|
||||||
this.openTerminal(host);
|
this.openTerminal(host);
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
|
||||||
|
// 获取当前终端会话
|
||||||
|
getCurrentTerminalSession(tips: boolean = true) {
|
||||||
|
const tab = this.tabManager.getCurrentTab();
|
||||||
|
if (!tab || tab.type !== TerminalTabType.TERMINAL) {
|
||||||
|
if (tips) {
|
||||||
|
Message.warning('请切换到终端标签页');
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 获取处理器并截图
|
||||||
|
return this.sessionManager.getSession(tab.key);
|
||||||
|
},
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -30,7 +30,7 @@
|
|||||||
|
|
||||||
const emits = defineEmits(['openSftp', 'openTransfer']);
|
const emits = defineEmits(['openSftp', 'openTransfer']);
|
||||||
|
|
||||||
const { tabManager, sessionManager } = useTerminalStore();
|
const { getCurrentTerminalSession } = useTerminalStore();
|
||||||
|
|
||||||
const snippetRef = ref();
|
const snippetRef = ref();
|
||||||
|
|
||||||
@@ -67,15 +67,10 @@
|
|||||||
|
|
||||||
// 终端截屏
|
// 终端截屏
|
||||||
const screenshot = () => {
|
const screenshot = () => {
|
||||||
const tab = tabManager.getCurrentTab();
|
const handler = getCurrentTerminalSession()?.handler;
|
||||||
if (!tab || tab.type !== TerminalTabType.TERMINAL) {
|
if (handler && handler.enabledStatus('screenshot')) {
|
||||||
Message.warning('请切换到终端标签页');
|
handler.screenshot();
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
// 获取处理器并截图
|
|
||||||
sessionManager.getSession(tab.key)
|
|
||||||
?.handler
|
|
||||||
?.screenshot();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
<!-- 启用-修改中 -->
|
<!-- 启用-修改中 -->
|
||||||
<a-input v-if="item.editable && item.enabled"
|
<a-input v-if="item.editable && item.enabled"
|
||||||
v-model="item.shortcutKey"
|
v-model="item.shortcutKey"
|
||||||
:ref="setEditRef"
|
:ref="setEditRef as unknown as VNodeRef"
|
||||||
class="trigger-input"
|
class="trigger-input"
|
||||||
size="small"
|
size="small"
|
||||||
placeholder="请按下快捷键"
|
placeholder="请按下快捷键"
|
||||||
@@ -66,6 +66,7 @@
|
|||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import type { TerminalShortcutKeyEditable } from '@/store/modules/terminal/types';
|
import type { TerminalShortcutKeyEditable } from '@/store/modules/terminal/types';
|
||||||
|
import type { VNodeRef } from 'vue';
|
||||||
import { nextTick } from 'vue';
|
import { nextTick } from 'vue';
|
||||||
|
|
||||||
defineProps<{
|
defineProps<{
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<a-drawer v-model:visible="visible"
|
<a-drawer v-model:visible="visible"
|
||||||
:width="388"
|
:width="388"
|
||||||
:footer="false">
|
:footer="false"
|
||||||
|
@close="onClose">
|
||||||
<!-- 表头 -->
|
<!-- 表头 -->
|
||||||
<template #title>
|
<template #title>
|
||||||
<span class="snippet-drawer-title">
|
<span class="snippet-drawer-title">
|
||||||
@@ -10,7 +11,7 @@
|
|||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
<!-- 命令容器 -->
|
<!-- 命令容器 -->
|
||||||
<a-spin class="snippet-container" :loading="loading">
|
<div class="snippet-container">
|
||||||
<!-- 命令头部 -->
|
<!-- 命令头部 -->
|
||||||
<div class="snippet-header">
|
<div class="snippet-header">
|
||||||
<!-- 创建命令 -->
|
<!-- 创建命令 -->
|
||||||
@@ -25,8 +26,22 @@
|
|||||||
@search="filterSnippet"
|
@search="filterSnippet"
|
||||||
@keyup.enter="filterSnippet" />
|
@keyup.enter="filterSnippet" />
|
||||||
</div>
|
</div>
|
||||||
|
<!-- 加载中 -->
|
||||||
|
<a-skeleton v-if="loading"
|
||||||
|
style="padding: 0 12px"
|
||||||
|
:animation="true">
|
||||||
|
<a-skeleton-line :rows="4"
|
||||||
|
:line-height="66"
|
||||||
|
:line-spacing="12" />
|
||||||
|
</a-skeleton>
|
||||||
|
<!-- 无数据 -->
|
||||||
|
<a-empty v-else-if="!snippet || (snippet.groups.length === 0 && snippet.ungroupedItems.length === 0)"
|
||||||
|
style="padding: 28px 0">
|
||||||
|
<span>暂无数据</span><br>
|
||||||
|
<span>点击上方 '<icon-plus />' 添加一条数据吧~</span>
|
||||||
|
</a-empty>
|
||||||
<!-- 命令片段 -->
|
<!-- 命令片段 -->
|
||||||
<div v-if="snippet" class="snippet-list-container">
|
<div v-else class="snippet-list-container">
|
||||||
<!-- 命令片段组 -->
|
<!-- 命令片段组 -->
|
||||||
<snippet-group :snippet="snippet" />
|
<snippet-group :snippet="snippet" />
|
||||||
<!-- 未分组命令片段 -->
|
<!-- 未分组命令片段 -->
|
||||||
@@ -38,7 +53,7 @@
|
|||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</a-spin>
|
</div>
|
||||||
</a-drawer>
|
</a-drawer>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -56,9 +71,11 @@
|
|||||||
import { getCommandSnippetList } from '@/api/asset/command-snippet';
|
import { getCommandSnippetList } from '@/api/asset/command-snippet';
|
||||||
import SnippetItem from './snippet-item.vue';
|
import SnippetItem from './snippet-item.vue';
|
||||||
import SnippetGroup from './snippet-group.vue';
|
import SnippetGroup from './snippet-group.vue';
|
||||||
|
import { useTerminalStore } from '@/store';
|
||||||
|
|
||||||
const { loading, setLoading } = useLoading();
|
const { loading, setLoading } = useLoading();
|
||||||
const { visible, setVisible } = useVisible();
|
const { visible, setVisible } = useVisible();
|
||||||
|
const { getCurrentTerminalSession } = useTerminalStore();
|
||||||
|
|
||||||
const filterValue = ref<string>();
|
const filterValue = ref<string>();
|
||||||
const snippet = ref<CommandSnippetWrapperResponse>();
|
const snippet = ref<CommandSnippetWrapperResponse>();
|
||||||
@@ -70,6 +87,8 @@
|
|||||||
await fetchData();
|
await fetchData();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// TODO 新增
|
||||||
|
|
||||||
defineExpose({ open });
|
defineExpose({ open });
|
||||||
|
|
||||||
// 加载数据
|
// 加载数据
|
||||||
@@ -106,13 +125,18 @@
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
// 关闭
|
||||||
open();
|
const onClose = () => {
|
||||||
});
|
setVisible(false);
|
||||||
|
// 聚焦终端
|
||||||
|
getCurrentTerminalSession(false)?.focus();
|
||||||
|
};
|
||||||
|
|
||||||
|
// fixme
|
||||||
|
onMounted(open);
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
.snippet-drawer-title {
|
.snippet-drawer-title {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
|
|||||||
@@ -1,10 +1,42 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="snippet-item-wrapper"
|
<div class="snippet-item-wrapper"
|
||||||
:class="[!!item.expand ? 'snippet-item-wrapper-expand' : '']">
|
:class="[!!item.expand ? 'snippet-item-wrapper-expand' : '']"
|
||||||
|
@click="expandItem">
|
||||||
<div class="snippet-item">
|
<div class="snippet-item">
|
||||||
<span class="snippet-item-title">
|
<div class="snippet-item-title">
|
||||||
{{ item.name }}
|
<!-- 名称 -->
|
||||||
</span>
|
<span class="snippet-item-title-name">
|
||||||
|
{{ item.name }}
|
||||||
|
</span>
|
||||||
|
<!-- 操作 -->
|
||||||
|
<div class="snippet-item-title-actions">
|
||||||
|
<a-space>
|
||||||
|
<!-- 粘贴 -->
|
||||||
|
<a-tag class="pointer usn"
|
||||||
|
size="small"
|
||||||
|
:checkable="true"
|
||||||
|
:checked="true"
|
||||||
|
@click.stop="paste">
|
||||||
|
<template #icon>
|
||||||
|
<icon-paste />
|
||||||
|
</template>
|
||||||
|
粘贴
|
||||||
|
</a-tag>
|
||||||
|
<!-- 执行 -->
|
||||||
|
<a-tag class="pointer usn"
|
||||||
|
size="small"
|
||||||
|
:checkable="true"
|
||||||
|
:checked="true"
|
||||||
|
@click.stop="exec">
|
||||||
|
<template #icon>
|
||||||
|
<icon-thunderbolt />
|
||||||
|
</template>
|
||||||
|
执行
|
||||||
|
</a-tag>
|
||||||
|
</a-space>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 命令 -->
|
||||||
<span class="snippet-item-command">
|
<span class="snippet-item-command">
|
||||||
{{ item.command }}
|
{{ item.command }}
|
||||||
</span>
|
</span>
|
||||||
@@ -20,11 +52,39 @@
|
|||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import type { CommandSnippetQueryResponse } from '@/api/asset/command-snippet';
|
import type { CommandSnippetQueryResponse } from '@/api/asset/command-snippet';
|
||||||
|
import { useTerminalStore } from '@/store';
|
||||||
|
|
||||||
defineProps<{
|
const props = defineProps<{
|
||||||
item: CommandSnippetQueryResponse
|
item: CommandSnippetQueryResponse
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
|
const { getCurrentTerminalSession } = useTerminalStore();
|
||||||
|
|
||||||
|
// TODO 右键菜单 复制 粘贴 删除 执行 修改
|
||||||
|
|
||||||
|
// 展开命令
|
||||||
|
const expandItem = () => {
|
||||||
|
props.item.expand = !props.item.expand;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 粘贴
|
||||||
|
const paste = () => {
|
||||||
|
write(props.item.command);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 执行
|
||||||
|
const exec = () => {
|
||||||
|
write(props.item.command + '\n');
|
||||||
|
};
|
||||||
|
|
||||||
|
// 写入命令
|
||||||
|
const write = (command: string) => {
|
||||||
|
const handler = getCurrentTerminalSession()?.handler;
|
||||||
|
if (handler && handler.enabledStatus('checkAppendMissing')) {
|
||||||
|
handler.checkAppendMissing(command);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
@@ -36,6 +96,7 @@
|
|||||||
@item-width: @drawer-width - @item-wrapper-p-x * 2;
|
@item-width: @drawer-width - @item-wrapper-p-x * 2;
|
||||||
@item-width-transform: @item-width + @transform-x;
|
@item-width-transform: @item-width + @transform-x;
|
||||||
@item-inline-width: @item-width - @item-p * 2;
|
@item-inline-width: @item-width - @item-p * 2;
|
||||||
|
@item-actions-width: 124px;
|
||||||
|
|
||||||
.snippet-item-wrapper {
|
.snippet-item-wrapper {
|
||||||
padding: @item-wrapper-p-y 0;
|
padding: @item-wrapper-p-y 0;
|
||||||
@@ -72,14 +133,37 @@
|
|||||||
&:hover {
|
&:hover {
|
||||||
width: @item-width-transform;
|
width: @item-width-transform;
|
||||||
background: var(--color-fill-3);
|
background: var(--color-fill-3);
|
||||||
|
|
||||||
|
.snippet-item-title {
|
||||||
|
&-name {
|
||||||
|
width: calc(@item-inline-width - @item-actions-width);
|
||||||
|
}
|
||||||
|
|
||||||
|
&-actions {
|
||||||
|
width: @item-actions-width;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&-title {
|
&-title {
|
||||||
color: var(--color-text-1);
|
color: var(--color-text-1);
|
||||||
margin-bottom: 8px;
|
margin-bottom: 8px;
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
width: @item-inline-width;
|
width: @item-inline-width;
|
||||||
|
height: 24px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
&-name {
|
||||||
|
width: @item-inline-width;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: pre;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-actions {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&-command {
|
&-command {
|
||||||
|
|||||||
Reference in New Issue
Block a user