🔨 文件上传.

This commit is contained in:
lijiahang
2024-02-21 16:32:29 +08:00
parent 63455d7654
commit f4d63d4b99
10 changed files with 180 additions and 30 deletions

View File

@@ -31,11 +31,8 @@ public class SftpFileVO {
@Schema(description = "文件后缀") @Schema(description = "文件后缀")
private String suffix; private String suffix;
@Schema(description = "文件大小")
private String size;
@Schema(description = "文件大小(byte)") @Schema(description = "文件大小(byte)")
private Long sizeByte; private Long size;
@Schema(description = "属性") @Schema(description = "属性")
private String attr; private String attr;

View File

@@ -157,8 +157,7 @@ public class SftpSession extends TerminalSession implements ISftpSession {
file.setName(sftpFile.getName()); file.setName(sftpFile.getName());
file.setPath(sftpFile.getPath()); file.setPath(sftpFile.getPath());
file.setSuffix(Files1.getSuffix(sftpFile.getName())); file.setSuffix(Files1.getSuffix(sftpFile.getName()));
file.setSize(Files1.getSize(sftpFile.getSize())); file.setSize(sftpFile.getSize());
file.setSizeByte(sftpFile.getSize());
file.setPermission(sftpFile.getPermission()); file.setPermission(sftpFile.getPermission());
file.setUid(sftpFile.getUid()); file.setUid(sftpFile.getUid());
file.setGid(sftpFile.getGid()); file.setGid(sftpFile.getGid());

View File

@@ -135,4 +135,24 @@ export function permission10toString(permission: number) {
return res; return res;
} }
// 获取文件大小
export function getFileSize(size: number, scale: number = 2) {
let result;
let unit;
if (size >= 1024 * 1024 * 1024) {
result = (size / (1024 * 1024 * 1024)).toFixed(scale);
unit = 'GB';
} else if (size >= 1024 * 1024) {
result = (size / (1024 * 1024)).toFixed(scale);
unit = 'MB';
} else if (size >= 1024) {
result = (size / 1024).toFixed(scale);
unit = 'KB';
} else {
result = size;
unit = 'B';
}
return `${result} ${unit}`;
}
export default null; export default null;

View File

@@ -68,7 +68,7 @@
</span> </span>
</a-tooltip> </a-tooltip>
<!-- 编辑内容 --> <!-- 编辑内容 -->
<a-tooltip v-if="canEditable(record.sizeByte, record.attr)" <a-tooltip v-if="canEditable(record.size, record.attr)"
position="top" position="top"
:mini="true" :mini="true"
:overlay-inverse="true" :overlay-inverse="true"
@@ -204,12 +204,12 @@
}; };
// 是否可编辑 // 是否可编辑
const canEditable = (sizeByte: number, attr: string) => { const canEditable = (size: number, attr: string) => {
const typeValue = formatFileType(attr).value; const typeValue = formatFileType(attr).value;
// 非文件夹和链接文件 并且文件小于 配置大小(MB) 可以编辑 // 非文件夹和链接文件 并且文件小于 配置大小(MB) 可以编辑
return FILE_TYPE.DIRECTORY.value !== typeValue return FILE_TYPE.DIRECTORY.value !== typeValue
&& FILE_TYPE.LINK_FILE.value !== typeValue && FILE_TYPE.LINK_FILE.value !== typeValue
&& sizeByte <= previewSize * 1024 * 1024; && size <= previewSize * 1024 * 1024;
}; };
// 点击文件名称 // 点击文件名称

View File

@@ -76,11 +76,11 @@
</script> </script>
<script lang="ts" setup> <script lang="ts" setup>
import type { SftpUploadItem } from '../../types/terminal.type';
import useVisible from '@/hooks/visible';
import { ref } from 'vue'; import { ref } from 'vue';
import { useTerminalStore } from '@/store'; import { useTerminalStore } from '@/store';
import { Message } from '@arco-design/web-vue'; import { Message } from '@arco-design/web-vue';
import useVisible from '@/hooks/visible';
import { TransferStatus, TransferType } from '../../types/terminal.const';
const { visible, setVisible } = useVisible(); const { visible, setVisible } = useVisible();
const { transferManager } = useTerminalStore(); const { transferManager } = useTerminalStore();
@@ -106,10 +106,15 @@
// 添加到上传列表 // 添加到上传列表
const files = fileList.value.map(s => { const files = fileList.value.map(s => {
return { return {
type: TransferType.UPLOAD,
hostId: hostId.value, hostId: hostId.value,
targetPath: parentPath.value + '/' + (s.file.webkitRelativePath || s.file.name), name: s.file.webkitRelativePath || s.file.name,
file: s.file as File currentSize: 0,
} as SftpUploadItem; totalSize: s.file.size,
status: TransferStatus.WAITING,
parentPath: parentPath.value,
file: s.file
};
}); });
transferManager.addUpload(files); transferManager.addUpload(files);
Message.success('已开始上传, 点击右侧传输列表查看进度'); Message.success('已开始上传, 点击右侧传输列表查看进度');

View File

@@ -1,4 +1,5 @@
import type { TableColumnData } from '@arco-design/web-vue/es/table/interface'; import type { TableColumnData } from '@arco-design/web-vue/es/table/interface';
import { getFileSize } from '@/utils/file';
// 表格列 // 表格列
const columns = [ const columns = [
@@ -17,12 +18,15 @@ const columns = [
} }
}, { }, {
title: '大小', title: '大小',
dataIndex: 'sizeByte', dataIndex: 'size',
slotName: 'size', slotName: 'size',
ellipsis: true, ellipsis: true,
sortable: { sortable: {
sortDirections: ['ascend', 'descend'], sortDirections: ['ascend', 'descend'],
}, },
render: ({ record }) => {
return getFileSize(record.size);
},
}, { }, {
title: '属性', title: '属性',
dataIndex: 'attr', dataIndex: 'attr',

View File

@@ -6,7 +6,71 @@
:unmount-on-close="false" :unmount-on-close="false"
:footer="false"> :footer="false">
<a-spin class="full" :loading="loading"> <a-spin class="full" :loading="loading">
{{ transferManager.transferList }} <a-list class="hosts-list-container"
size="smail"
max-height="100%"
:hoverable="true"
:bordered="false"
:data="transferManager.transferList">
<!-- 空数据 -->
<template #empty>
<a-empty description="无数据" />
</template>
<!-- 数据 -->
<template #item="{ item }">
<a-list-item class="transfer-item-wrapper">
<div class="transfer-item">
<!-- 左侧图标 -->
<div class="transfer-item-left">
<span class="file-icon">
<icon-upload />
</span>
</div>
<!-- 中间信息 -->
<div class="transfer-item-center">
<!-- 文件名称 -->
<a-tooltip position="top"
:mini="true"
:auto-fix-position="false"
content-class="terminal-tooltip-content"
arrow-class="terminal-tooltip-content"
:content="item.name">
<span class="file-name">
{{ item.name }}
</span>
</a-tooltip>
<!-- 传输进度 -->
<span class="transfer-progress">
{{ getFileSize(item.currentSize) }}/{{ getFileSize(item.totalSize) }}
</span>
<!-- 目标目录 -->
<a-tooltip v-if="item.parentPath"
position="top"
:mini="true"
:auto-fix-position="false"
content-class="terminal-tooltip-content"
arrow-class="terminal-tooltip-content"
:content="item.parentPath">
<span class="target-path">
{{ item.parentPath }}
</span>
</a-tooltip>
</div>
<!-- 右侧状态/操作-->
<div class="transfer-item-right">
<!-- 等待传输 -->
<icon-loading v-if="item.status === TransferStatus.WAITING" />
<!-- 传输进度 -->
<a-progress v-else
type="circle"
size="mini"
:status="item.status"
:percent="item.currentSize / item.totalSize" />
</div>
</div>
</a-list-item>
</template>
</a-list>
</a-spin> </a-spin>
</a-drawer> </a-drawer>
</template> </template>
@@ -21,6 +85,8 @@
import useLoading from '@/hooks/loading'; import useLoading from '@/hooks/loading';
import useVisible from '@/hooks/visible'; import useVisible from '@/hooks/visible';
import { useTerminalStore } from '@/store'; import { useTerminalStore } from '@/store';
import { getFileSize } from '@/utils/file';
import { TransferStatus } from '../../types/terminal.const';
const { transferManager } = useTerminalStore(); const { transferManager } = useTerminalStore();
const { visible, setVisible } = useVisible(); const { visible, setVisible } = useVisible();
@@ -46,12 +112,53 @@
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
.form-container { @item-left-width: 42px;
padding: 12px; @item-right-width: 42px;
@item-center-width: 388px - @item-left-width - @item-right-width;
.transfer-item {
min-height: 36px;
padding: 8px 0;
display: flex;
align-items: center;
&-left {
width: @item-left-width;
display: flex;
justify-content: center;
.file-icon {
color: rgb(var(--arcoblue-6));
font-size: 18px;
}
} }
.command-editor { &-center {
height: calc(100vh - 330px); width: @item-center-width;
display: flex;
flex-direction: column;
.file-name {
color: var(--color-content-text-1);
overflow: hidden;
text-overflow: ellipsis;
width: fit-content;
max-width: 100%;
}
.transfer-progress, .target-path {
padding-top: 4px;
font-size: 13px;
color: var(--color-neutral-8);
width: fit-content;
}
}
&-right {
width: @item-right-width;
display: flex;
justify-content: center;
}
} }
</style> </style>

View File

@@ -1,16 +1,16 @@
import type { ISftpTransferManager, SftpUploadItem } from '../types/terminal.type'; import type { ISftpTransferManager, SftpTransferItem } from '../types/terminal.type';
// sftp 传输管理器实现 // sftp 传输管理器实现
export default class SftpTransferManager implements ISftpTransferManager { export default class SftpTransferManager implements ISftpTransferManager {
transferList: Array<SftpUploadItem>; transferList: Array<SftpTransferItem>;
constructor() { constructor() {
this.transferList = []; this.transferList = [];
} }
// 添加上传文件 // 添加上传文件
addUpload(items: Array<SftpUploadItem>): void { addUpload(items: Array<SftpTransferItem>): void {
this.transferList.push(...items); this.transferList.push(...items);
} }

View File

@@ -285,6 +285,20 @@ export const TerminalShortcutItems: Array<ShortcutKeyItem> = [
}, },
]; ];
// 传输状态
export const TransferStatus = {
WAITING: 'waiting',
TRANSFERRING: 'normal',
SUCCESS: 'success',
ERROR: 'danger',
};
// 传输类型
export const TransferType = {
UPLOAD: 'upload',
DOWNLOAD: 'download'
};
// 打开 sshSettingModal key // 打开 sshSettingModal key
export const openSshSettingModalKey = Symbol(); export const openSshSettingModalKey = Symbol();

View File

@@ -358,8 +358,7 @@ export interface SftpFile {
name: string; name: string;
path: string; path: string;
suffix: string; suffix: string;
size: string; size: number;
sizeByte: number;
attr: string; attr: string;
isDir: boolean; isDir: boolean;
permission: number; permission: number;
@@ -370,14 +369,19 @@ export interface SftpFile {
// sftp 传输管理器定义 // sftp 传输管理器定义
export interface ISftpTransferManager { export interface ISftpTransferManager {
transferList: Array<SftpUploadItem>; transferList: Array<SftpTransferItem>;
// 添加上传文件 // 添加上传文件
addUpload: (items: Array<SftpUploadItem>) => void; addUpload: (items: Array<SftpTransferItem>) => void;
} }
// sftp 上传文件项 // sftp 上传文件项
export interface SftpUploadItem { export interface SftpTransferItem {
type: string;
hostId: number; hostId: number;
targetPath: string; name: string;
parentPath: string;
currentSize: number,
totalSize: number;
status: string;
file: File; file: File;
} }