🔨 sftp 表头.

This commit is contained in:
lijiahangmax
2024-02-07 16:24:41 +08:00
parent 734f7a40cd
commit e7cf5f61ef
6 changed files with 415 additions and 59 deletions

View File

@@ -7,7 +7,7 @@ import { TablePageSizeOptions } from '@/types/const';
/**
* 创建列表分页
*/
export const usePagination = (): PaginationProps => {
export const usePagination = (ext?: PaginationProps): PaginationProps => {
const appStore = useAppStore();
return reactive({
total: 0,
@@ -15,17 +15,19 @@ export const usePagination = (): PaginationProps => {
pageSize: isNumber(appStore.defaultTablePageSize) ? appStore.defaultTablePageSize : TablePageSizeOptions[0],
showTotal: true,
showPageSize: true,
pageSizeOptions: TablePageSizeOptions
pageSizeOptions: TablePageSizeOptions,
...ext
});
};
/**
* 创建行选择器
*/
export const useRowSelection = (type = 'checkbox'): TableRowSelection => {
export const useRowSelection = (ext?: TableRowSelection): TableRowSelection => {
return reactive({
type: type as any,
type: 'checkbox',
showCheckedAll: true,
onlyCurrent: true,
...ext
});
};

View File

@@ -0,0 +1,201 @@
<template>
<!-- 表头 -->
<div class="sftp-table-header">
<!-- 左侧操作 -->
<div class="sftp-table-header-left">
<!-- 返回上级 -->
<a-tooltip position="top"
:mini="true"
:overlay-inverse="true"
:auto-fix-position="false"
content-class="terminal-tooltip-content"
arrow-class="terminal-tooltip-content"
content="返回上级">
<span class="click-icon-wrapper header-action-icon mr4">
<icon-left />
</span>
</a-tooltip>
<!-- 当前路径 -->
<div class="sftp-path-wrapper">
<a-breadcrumb>
<!-- 分隔符 -->
<template #separator>
<icon-right />
</template>
<a-breadcrumb-item class="sftp-path-unit">/</a-breadcrumb-item>
<a-breadcrumb-item class="sftp-path-unit">root</a-breadcrumb-item>
<a-breadcrumb-item class="sftp-path-unit">orion</a-breadcrumb-item>
<a-breadcrumb-item class="sftp-path-unit">space</a-breadcrumb-item>
<a-breadcrumb-item class="sftp-path-unit">logs</a-breadcrumb-item>
</a-breadcrumb>
</div>
</div>
<!-- 右侧操作 -->
<a-space class="sftp-table-header-right">
<!-- 刷新 -->
<a-tooltip position="top"
:mini="true"
:overlay-inverse="true"
:auto-fix-position="false"
content-class="terminal-tooltip-content"
arrow-class="terminal-tooltip-content"
content="刷新">
<span class="click-icon-wrapper header-action-icon">
<icon-refresh />
</span>
</a-tooltip>
<!-- 显示隐藏文件 -->
<a-tooltip position="top"
:mini="true"
:overlay-inverse="true"
:auto-fix-position="false"
content-class="terminal-tooltip-content"
arrow-class="terminal-tooltip-content"
content="显示隐藏文件">
<span class="click-icon-wrapper header-action-icon">
<icon-eye />
</span>
</a-tooltip>
<!-- 创建文件 -->
<a-tooltip position="top"
:mini="true"
:overlay-inverse="true"
:auto-fix-position="false"
content-class="terminal-tooltip-content"
arrow-class="terminal-tooltip-content"
content="创建文件">
<span class="click-icon-wrapper header-action-icon">
<icon-drive-file />
</span>
</a-tooltip>
<!-- 创建文件夹 -->
<a-tooltip position="top"
:mini="true"
:overlay-inverse="true"
:auto-fix-position="false"
content-class="terminal-tooltip-content"
arrow-class="terminal-tooltip-content"
content="创建文件夹">
<span class="click-icon-wrapper header-action-icon">
<icon-folder-add />
</span>
</a-tooltip>
<!-- 删除 -->
<a-tooltip position="top"
:mini="true"
:overlay-inverse="true"
:auto-fix-position="false"
content-class="terminal-tooltip-content"
arrow-class="terminal-tooltip-content"
content="删除">
<span class="click-icon-wrapper header-action-icon">
<icon-delete />
</span>
</a-tooltip>
<!-- 复制 -->
<a-tooltip position="top"
:mini="true"
:overlay-inverse="true"
:auto-fix-position="false"
content-class="terminal-tooltip-content"
arrow-class="terminal-tooltip-content"
content="复制">
<span class="click-icon-wrapper header-action-icon">
<icon-copy />
</span>
</a-tooltip>
<!-- 移动 -->
<a-tooltip position="top"
:mini="true"
:overlay-inverse="true"
:auto-fix-position="false"
content-class="terminal-tooltip-content"
arrow-class="terminal-tooltip-content"
content="移动">
<span class="click-icon-wrapper header-action-icon">
<icon-paste />
</span>
</a-tooltip>
<!-- 上传 -->
<a-tooltip position="top"
:mini="true"
:overlay-inverse="true"
:auto-fix-position="false"
content-class="terminal-tooltip-content"
arrow-class="terminal-tooltip-content"
content="上传">
<span class="click-icon-wrapper header-action-icon">
<icon-upload />
</span>
</a-tooltip>
<!-- 下载 -->
<a-tooltip position="top"
:mini="true"
:overlay-inverse="true"
:auto-fix-position="false"
content-class="terminal-tooltip-content"
arrow-class="terminal-tooltip-content"
content="下载">
<span class="click-icon-wrapper header-action-icon">
<icon-download />
</span>
</a-tooltip>
</a-space>
</div>
</template>
<script lang="ts">
export default {
name: 'sftpTableHeader'
};
</script>
<script lang="ts" setup>
</script>
<style lang="less" scoped>
.sftp-table-header {
width: 100%;
display: flex;
align-items: center;
justify-content: space-between;
&-left, &-right {
display: flex;
align-items: center;
height: 100%;
}
&-left {
width: calc(100% - 302px);
}
&-right {
width: 302px;
justify-content: flex-end;
}
}
.sftp-path-wrapper {
background: var(--color-fill-2);
width: 100%;
border-radius: 2px;
padding: 1px 6px;
overflow: hidden;
:deep(.sftp-path-unit) {
cursor: pointer;
&:hover {
color: rgb(var(--arcoblue-6));
}
}
}
.header-action-icon {
font-size: 16px;
padding: 4px;
}
</style>

View File

@@ -27,10 +27,88 @@
</a-space>
</div>
</template>
<!-- 文件名称 -->
<template #fileName="{ record }">
<!-- 文件图标 -->
<span class="file-name-icon" :title="formatFileType(record.attr).label">
<component :is="formatFileType(record.attr).icon" />
</span>
<span>
{{ record.name }}
</span>
</template>
<!-- 文件大小 -->
<template #size="{ record }">
<span v-if="editRecord.name === record.name">操作</span>
<span v-else>{{ record.size }}</span>
<span>{{ record.size }}</span>
</template>
<!-- 修改时间/操作 -->
<template #modifyTime="{ record }">
<!-- 修改时间 -->
<span v-if="editName !== record.name">{{ dateFormat(new Date(record.modifyTime)) }}</span>
<!-- 操作 -->
<a-space v-else>
<!-- 复制路径 -->
<a-tooltip position="top"
:mini="true"
:overlay-inverse="true"
:auto-fix-position="false"
content-class="terminal-tooltip-content"
arrow-class="terminal-tooltip-content"
content="复制路径">
<span class="click-icon-wrapper row-action-icon"
@click="copy(record.path, false)">
<icon-copy />
</span>
</a-tooltip>
<!-- 删除 -->
<a-tooltip position="top"
:mini="true"
:auto-fix-position="false"
content-class="terminal-tooltip-content"
arrow-class="terminal-tooltip-content"
content="删除">
<span class="click-icon-wrapper row-action-icon"
@click="deleteFile(record.path)">
<icon-delete />
</span>
</a-tooltip>
<!-- 下载 -->
<a-tooltip position="top"
:mini="true"
:auto-fix-position="false"
content-class="terminal-tooltip-content"
arrow-class="terminal-tooltip-content"
content="下载">
<span class="click-icon-wrapper row-action-icon"
@click="downloadFile(record.path)">
<icon-download />
</span>
</a-tooltip>
<!-- 移动 -->
<a-tooltip position="top"
:mini="true"
:auto-fix-position="false"
content-class="terminal-tooltip-content"
arrow-class="terminal-tooltip-content"
content="移动">
<span class="click-icon-wrapper row-action-icon"
@click="moveFile(record.path)">
<icon-paste />
</span>
</a-tooltip>
<!-- 提权 -->
<a-tooltip position="top"
:mini="true"
:auto-fix-position="false"
content-class="terminal-tooltip-content"
arrow-class="terminal-tooltip-content"
content="提权">
<span class="click-icon-wrapper row-action-icon"
@click="chmodFile(record.path)">
<icon-user-group />
</span>
</a-tooltip>
</a-space>
</template>
</a-table>
</template>
@@ -46,33 +124,62 @@
import type { SftpFile } from '../../types/terminal.type';
import { ref } from 'vue';
import { useRowSelection } from '@/types/table';
import { dateFormat } from '@/utils';
import columns from './types/table.columns';
import useCopy from '@/hooks/copy';
import { FILE_TYPE } from '../../types/terminal.const';
const props = defineProps<{
list: Array<SftpFile>;
loading: boolean;
}>();
const rowSelection = useRowSelection();
const rowSelection = useRowSelection({ width: 40 });
const { copy } = useCopy();
const selectedKeys = ref<Array<string>>([]);
const editRecord = ref<TableData>({});
const editName = ref<string>('');
// 设置选中状态
const setEditable = (record: TableData) => {
editRecord.value = record;
editName.value = record.name;
record.hover = true;
};
// 设置未选中状态
const unsetEditable = (record: TableData) => {
setTimeout(() => {
if (record.name === editRecord.value.name && !record.hover) {
editRecord.value = {};
// 等待后如果还是当前行 但是未被选中则代表已经被失焦
if (record.name === editName.value && !record.hover) {
editName.value = '';
}
}, 20);
record.hover = false;
};
// 删除文件
const deleteFile = (path: string) => {
};
// 下载文件
const downloadFile = (path: string) => {
};
// 移动文件
const moveFile = (path: string) => {
};
// 文件提权
const chmodFile = (path: string) => {
};
// 格式化文件类型
const formatFileType = (attr: string) => {
return Object.values(FILE_TYPE).find(s => {
return s.value === attr.charAt(0);
}) || FILE_TYPE.NORMAL_FILE;
};
</script>
<style lang="less" scoped>
@@ -94,4 +201,28 @@
}
}
.file-name-icon {
font-size: 16px;
line-height: 16px;
margin-right: 6px;
}
.row-action-icon {
font-size: 16px;
padding: 4px;
background: unset;
&:hover {
background: var(--color-fill-3);
}
}
:deep(.action-cell .arco-table-cell) {
padding: 0;
}
:deep(.arco-table-th-title) {
user-select: none;
}
</style>

View File

@@ -1,24 +1,19 @@
<template>
<div class="sftp-container">
<!-- 头部 -->
<div class="sftp-header">
<!-- 左侧操作 -->
<div class="sftp-header-left">
home input
</div>
<!-- 右侧操作 -->
<div class="sftp-header-right">
上传 下载 删除 刷新 copy touch mk
</div>
</div>
<a-split class="split-view"
v-model:size="splitSize"
:min="0.3"
:disabled="!editView">
<!-- 表格 -->
<!-- 左侧面板表格 -->
<template #first>
<sftp-table :list="list"
:loading="loading" />
<div class="sftp-table-container">
<!-- 表头 -->
<sftp-table-header class="sftp-table-header" />
<!-- 表格 -->
<sftp-table class="sftp-table-wrapper"
:list="list"
:loading="loading" />
</div>
</template>
<template #second v-if="editView">
<div>editor</div>
@@ -39,7 +34,8 @@
import { useTerminalStore } from '@/store';
import useLoading from '@/hooks/loading';
import data from './data';
import SftpTable from '@/views/host/terminal/components/sftp/sftp-table.vue';
import SftpTable from './sftp-table.vue';
import SftpTableHeader from './sftp-table-header.vue';
const props = defineProps<{
tab: TerminalTabItem
@@ -72,36 +68,31 @@
</script>
<style lang="less" scoped>
@sftp-header-height: 36px;
@sftp-table-header-height: 32px + 8px;
.sftp-container {
width: 100%;
height: calc(100vh - var(--header-height) - var(--panel-nav-height));
position: relative;
}
.split-view {
width: 100%;
height: calc(100% - @sftp-header-height);
}
.sftp-header {
width: 100%;
height: @sftp-header-height;
padding: 0 8px;
display: flex;
align-items: center;
justify-content: space-between;
background: var(--color-bg-panel-bar);
&-left, &-right {
display: flex;
align-items: center;
.split-view {
width: 100%;
height: 100%;
}
}
&-right {
justify-content: flex-end;
.sftp-table-container {
padding: 8px;
height: 100%;
.sftp-table-header {
width: 100%;
height: @sftp-table-header-height;
padding-bottom: 8px;
}
.sftp-table-wrapper {
height: calc(100% - @sftp-table-header-height);
}
}

View File

@@ -1,13 +1,13 @@
import type { TableColumnData } from '@arco-design/web-vue/es/table/interface';
import { dateFormat } from '@/utils';
// 表格列
const columns = [
{
title: '名称',
dataIndex: 'name',
slotName: 'name',
fixed: 'left',
slotName: 'fileName',
ellipsis: true,
tooltip: true,
sortable: {
sortDirections: ['ascend', 'descend'],
},
@@ -34,15 +34,7 @@ const columns = [
sortable: {
sortDirections: ['ascend', 'descend'],
},
render: ({ record }) => {
return dateFormat(new Date(record.modifyTime));
},
}, {
title: '操作',
dataIndex: 'actions',
slotName: 'actions',
align: 'left',
fixed: 'right',
cellClass: 'action-cell',
},
] as TableColumnData[];

View File

@@ -52,6 +52,45 @@ export const ExtraSshAuthType = {
CUSTOM_IDENTITY: 'CUSTOM_IDENTITY',
};
// 文件类型
export const FILE_TYPE = {
NORMAL_FILE: {
value: '-',
label: '普通文件',
icon: 'icon-file'
},
DIRECTORY: {
value: 'd',
label: '目录',
icon: 'icon-folder'
},
LINK_FILE: {
value: 'l',
label: '链接文件',
icon: 'icon-link'
},
MANAGE_FILE: {
value: 'p',
label: '管理文件',
icon: 'icon-drive-file'
},
BLOCK_DEVICE_FILE: {
value: 'b',
label: '块设备文件',
icon: 'icon-drive-file'
},
CHARACTER_DEVICE_FILE: {
value: 'c',
label: '字符设备文件',
icon: 'icon-drive-file'
},
SOCKET_FILE: {
value: 's',
label: '套接字文件',
icon: 'icon-drive-file'
}
};
// 面板会话 tab 类型
export const PanelSessionType = {
SSH: {