feat: 命令片段.

This commit is contained in:
lijiahang
2024-01-24 19:19:26 +08:00
parent 7d614f0bdc
commit af4d4d99a6
13 changed files with 333 additions and 220 deletions

View File

@@ -5,6 +5,7 @@ body {
--color-bg-content: #FEFEFE;
--color-sidebar-icon: #737070;
--color-sidebar-icon-bg: #D7D8DB;
--color-sidebar-icon-checked: #CBCCCF;
--color-sidebar-tooltip-text: rgba(255, 255, 255, .9);
--color-sidebar-tooltip-bg: rgb(29, 33, 41);
--color-content-text-1: rgba(0, 0, 0, .8);
@@ -25,8 +26,9 @@ body[terminal-theme='dark'] {
--color-bg-header: #232323;
--color-bg-sidebar: #2C2E31;
--color-bg-content: #1A1B1C;
--color-sidebar-icon: #C3C8CE;
--color-sidebar-icon-bg: #43444C;
--color-sidebar-icon: #C3C6C9;
--color-sidebar-icon-bg: #3D3E3F;
--color-sidebar-icon-checked: #51525C;
--color-sidebar-tooltip-text: rgba(255, 255, 255, .9);
--color-sidebar-tooltip-bg: var(--color-sidebar-icon-bg);
--color-content-text-1: rgba(255, 255, 255, .8);
@@ -214,7 +216,7 @@ body[terminal-theme='dark'] .arco-modal-container {
}
&.checked-item {
background: var(--color-sidebar-icon-bg);
background: var(--color-sidebar-icon-checked);
}
&.disabled-item {

View File

@@ -99,15 +99,20 @@
</script>
<style lang="less" scoped>
@transform-x: 8px;
@container-width: 406px;
@container-height: 448px;
@handler-height: 44px;
.combined-container {
padding: 12px;
margin: 64px auto;
width: 398px;
height: 448px;
width: @container-width;
height: @container-height;
display: flex;
flex-direction: column;
align-items: center;
box-sizing: content-box;
overflow: hidden;
&:hover {
@@ -116,20 +121,19 @@
}
.combined-handler {
width: 100%;
width: calc(@container-width - @transform-x);
height: @handler-height;
border-radius: 4px;
margin-bottom: 6px;
color: var(--color-content-text-1);
background-color: var(--color-fill-2);
display: flex;
align-items: center;
color: var(--color-content-text-1);
cursor: pointer;
transition: transform 0.3s ease;
will-change: transform;
transition: all 0.2s;
&:hover {
transform: scale(1.04);
width: @container-width;
}
&-icon {

View File

@@ -84,7 +84,6 @@
</script>
<style lang="less" scoped>
.form-item-actions {
display: flex;
background-color: var(--color-fill-2);

View File

@@ -119,7 +119,8 @@
<style lang="less" scoped>
@container-width: 418px;
@wrapper-margin-r: 32px;
@wrapper-width: (@container-width - @wrapper-margin-r) / 2px;
@transform-x: 8px;
@item-width: (@container-width - @wrapper-margin-r) / 2;
.setting-body {
display: flex;
@@ -130,23 +131,26 @@
height: auto;
.actions-wrapper {
width: @wrapper-width;
padding-right: 8px;
margin-right: @wrapper-margin-r;
}
.action-item-wrapper {
transition: all 0.2s;
width: 185px;
border-radius: 4px;
width: calc((@item-width) - @transform-x);
&:hover {
width: 192px;
width: calc(@item-width);
padding: 4px 0 !important;
.action-item{
.action-item {
background: var(--color-fill-3);
}
.action-icon {
background: var(--color-fill-4);
}
}
}

View File

@@ -12,48 +12,23 @@
<!-- 命令容器 -->
<div class="snippet-container">
<!-- 命令头部 -->
<div class="snippet-header-container">
<!-- 头部操作 -->
<div class="snippet-header">
<a-button @click="toggle">新建</a-button>
<a-button>搜索</a-button>
</div>
<!-- 提示 -->
<a-alert v-if="isNotTipped(snippetTipsKey)"
class="snippet-tips"
:closable="true"
@on-close="closeTips">
双击命令直接运行
</a-alert>
<div class="snippet-header">
<!-- 创建命令 -->
<span class="click-icon-wrapper snippet-header-icon" title="创建命令">
<icon-plus />
</span>
<!-- 搜索框 -->
<a-input-search class="snippet-header-input"
placeholder="名称"
allow-clear />
</div>
<!-- 命令片段 -->
<div class="snippet-list-container">
<a-collapse v-if="snippet.groups.length"
:bordered="false">
<a-collapse-item v-for="group in snippet.groups"
:key="group.id"
:header="group.name">
<!-- 总量 -->
<template #extra>
{{ group.idList.length }}
</template>
{{ group }}
</a-collapse-item>
</a-collapse>
<snippet-group :snippet="snippet" />
<div>
<div v-for="item in snippet.snippets"
:key="item.id"
class="snippet-item-wrapper"
:class="[loading&&item.id===3 ? 'snippet-item-wrapper-expand' : '']">
<div class="snippet-item">
<span class="snippet-item-title">
{{ item.name }}
</span>
<span class="snippet-item-command">
{{ item.command }}
</span>
</div>
</div>
<snippet-item v-for="item in snippet.items"
:key="item.id"
:item="item" />
</div>
</div>
</div>
@@ -67,96 +42,38 @@
</script>
<script lang="ts" setup>
import { ref } from 'vue';
export interface SnippetGroupResponse {
groups: Array<SnippetGroup>;
snippets: Array<Snippet>;
}
export interface SnippetGroup {
id: number;
name: string;
idList: Array<number>;
}
export interface Snippet {
id: number;
name: string;
command: string;
}
import { useTipsStore } from '@/store';
import type { CommandSnippetWrapperResponse } from '@/api/asset/command-snippet';
import { onMounted, ref } from 'vue';
import useVisible from '@/hooks/visible';
import { snippetTipsKey } from '../../types/terminal.const';
import useLoading from '@/hooks/loading';
import SnippetItem from './snippet-item.vue';
import SnippetGroup from './snippet-group.vue';
const { isNotTipped, setTipped } = useTipsStore();
const { loading, toggle } = useLoading();
const { visible, setVisible } = useVisible(true);
const snippet = ref<SnippetGroupResponse>({
groups: [{
id: 1,
name: 'group1',
idList: [1, 2]
}, {
id: 2,
name: 'group2',
idList: [3, 4]
}],
snippets: [{
id: 1,
name: 'command1command1command1command1command1command1command1command1command1command1command1command1command1command1command1',
command: 'echo Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ad adipisci aliquid, atque cupiditate doloribus eligendi enim fugiat itaque iusto laborum magnam maiores natus nemo, neque quae, reprehenderit sed ullam voluptatem?'
}, {
id: 2,
name: 'command2',
command: 'echo Lorem'
}, {
id: 3,
name: 'command3',
command: 'echo Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ad adipisci aliquid, atque cupiditate doloribus eligendi enim fugiat itaque iusto laborum magnam maiores natus nemo, neque quae, reprehenderit sed ullam voluptatem?'
}, {
id: 4,
name: 'command4',
command: 'echo Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ad adipisci aliquid, atque cupiditate doloribus eligendi enim fugiat itaque iusto laborum magnam maiores natus nemo, neque quae, reprehenderit sed ullam voluptatem?'
}, {
id: 5,
name: 'command5',
command: 'echo Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ad adipisci aliquid, atque cupiditate doloribus eligendi enim fugiat itaque iusto laborum magnam maiores natus nemo, neque quae, reprehenderit sed ullam voluptatem?'
}, {
id: 6,
name: 'command6',
command: 'echo Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ad adipisci aliquid, atque cupiditate doloribus eligendi enim fugiat itaque iusto laborum magnam maiores natus nemo, neque quae, reprehenderit sed ullam voluptatem?'
}]
const { visible, setVisible } = useVisible();
const snippet = ref<CommandSnippetWrapperResponse>({
groups: [],
items: []
});
// 打开
const open = () => {
setVisible(true);
console.log('loading');
// loading
};
// 关闭提示
const closeTips = () => {
console.log('close');
};
defineExpose({ open });
onMounted(() => {
open();
});
</script>
<style lang="less" scoped>
@transform-x: 8px;
@drawer-width: 388px;
@item-wrapper-p-y: 4px;
@item-wrapper-p-x: 12px;
@item-p: 8px;
@item-width: @drawer-width - @item-wrapper-p-x * 2;
@item-width-transform: @item-width + @transform-x;
@item-inline-width: @item-width - @item-p * 2;
.snippet-drawer-title {
font-size: 14px;
}
@@ -166,104 +83,30 @@
background: var(--color-bg-2);
height: 100%;
.snippet-header-container {
.snippet-header {
padding: 12px;
//height: 104px;
height: 56px;
display: flex;
align-items: center;
justify-content: space-between;
.snippet-header {
&-icon {
width: 32px;
height: 32px;
font-size: 16px;
}
.snippet-tips {
margin-top: 8px;
&-input {
width: 220px;
}
}
}
.snippet-list-container {
position: relative;
//height: calc(100% - 104px);
height: calc(100% - 56px);
overflow: auto;
}
.snippet-item-wrapper {
padding: @item-wrapper-p-y 0;
display: flex;
justify-content: center;
align-items: center;
width: 100%;
&-expand {
.snippet-item {
width: @item-width-transform !important;
background: var(--color-fill-3) !important;
:hover {
}
.snippet-item-command {
color: var(--color-text-1);
text-overflow: unset;
word-break: break-all;
white-space: unset;
}
}
}
.snippet-item {
display: flex;
flex-direction: column;
padding: @item-p;
background: var(--color-fill-2);
border-radius: 4px;
cursor: pointer;
transition: all 0.2s;
width: @item-width;
&:hover {
width: @item-width-transform;
background: var(--color-fill-3);
}
&-title {
color: var(--color-text-1);
margin-bottom: 8px;
overflow: hidden;
text-overflow: ellipsis;
width: @item-inline-width;
}
&-command {
color: var(--color-text-2);
font-size: 12px;
overflow: hidden;
text-overflow: ellipsis;
white-space: pre;
width: @item-inline-width;
}
}
}
:deep(.arco-collapse-item) {
border: none;
.arco-collapse-item-header-title {
user-select: none;
}
.arco-collapse-item-header {
border: none;
}
.arco-collapse-item-content {
background-color: unset;
padding: 0;
}
.arco-collapse-item-content-box {
padding: 0;
}
padding-bottom: 4px;
}
</style>

View File

@@ -0,0 +1,54 @@
<template>
<a-collapse :bordered="false">
<a-collapse-item v-for="group in snippet.groups"
:key="group.id"
:header="group.name">
<!-- 总量 -->
<template #extra>
{{ 1 }}
</template>
<snippet-item v-for="item in snippet.items"
:key="item.id"
:item="item" />
</a-collapse-item>
</a-collapse>
</template>
<script lang="ts">
export default {
name: 'snippetGroup'
};
</script>
<script lang="ts" setup>
import type { CommandSnippetWrapperResponse } from '@/api/asset/command-snippet';
import SnippetItem from './snippet-item.vue';
defineProps<{
snippet: CommandSnippetWrapperResponse
}>();
</script>
<style lang="less" scoped>
:deep(.arco-collapse-item) {
border: none;
.arco-collapse-item-header-title {
user-select: none;
}
.arco-collapse-item-header {
border: none;
}
.arco-collapse-item-content {
background-color: unset;
padding: 0;
}
.arco-collapse-item-content-box {
padding: 0;
}
}
</style>

View File

@@ -0,0 +1,95 @@
<template>
<div class="snippet-item-wrapper"
:class="[!!item.expand ? 'snippet-item-wrapper-expand' : '']">
<div class="snippet-item">
<span class="snippet-item-title">
{{ item.name }}
</span>
<span class="snippet-item-command">
{{ item.command }}
</span>
</div>
</div>
</template>
<script lang="ts">
export default {
name: 'snippetItem'
};
</script>
<script lang="ts" setup>
import type { CommandSnippetQueryResponse } from '@/api/asset/command-snippet';
defineProps<{
item: CommandSnippetQueryResponse
}>();
</script>
<style lang="less" scoped>
@transform-x: 8px;
@drawer-width: 388px;
@item-wrapper-p-y: 4px;
@item-wrapper-p-x: 12px;
@item-p: 8px;
@item-width: @drawer-width - @item-wrapper-p-x * 2;
@item-width-transform: @item-width + @transform-x;
@item-inline-width: @item-width - @item-p * 2;
.snippet-item-wrapper {
padding: @item-wrapper-p-y 0;
display: flex;
justify-content: center;
align-items: center;
width: 100%;
&-expand {
.snippet-item {
width: @item-width-transform !important;
background: var(--color-fill-3) !important;
.snippet-item-command {
color: var(--color-text-1);
text-overflow: unset;
word-break: break-all;
white-space: unset;
}
}
}
.snippet-item {
display: flex;
flex-direction: column;
padding: @item-p;
background: var(--color-fill-2);
border-radius: 4px;
cursor: pointer;
transition: all 0.2s;
width: @item-width;
&:hover {
width: @item-width-transform;
background: var(--color-fill-3);
}
&-title {
color: var(--color-text-1);
margin-bottom: 8px;
overflow: hidden;
text-overflow: ellipsis;
width: @item-inline-width;
}
&-command {
color: var(--color-text-2);
font-size: 12px;
overflow: hidden;
text-overflow: ellipsis;
white-space: pre;
width: @item-inline-width;
}
}
}
</style>

View File

@@ -208,9 +208,6 @@ export const TerminalShortcutItems: Array<ShortcutKeyItem> = [
},
];
// 命令片段操作提示
export const snippetTipsKey = 'snippet:opt';
// 打开 sshModal key
export const openSshModalKey = Symbol();