🔨 文件上传.
This commit is contained in:
@@ -31,11 +31,8 @@ public class SftpFileVO {
|
||||
@Schema(description = "文件后缀")
|
||||
private String suffix;
|
||||
|
||||
@Schema(description = "文件大小")
|
||||
private String size;
|
||||
|
||||
@Schema(description = "文件大小(byte)")
|
||||
private Long sizeByte;
|
||||
private Long size;
|
||||
|
||||
@Schema(description = "属性")
|
||||
private String attr;
|
||||
|
||||
@@ -157,8 +157,7 @@ public class SftpSession extends TerminalSession implements ISftpSession {
|
||||
file.setName(sftpFile.getName());
|
||||
file.setPath(sftpFile.getPath());
|
||||
file.setSuffix(Files1.getSuffix(sftpFile.getName()));
|
||||
file.setSize(Files1.getSize(sftpFile.getSize()));
|
||||
file.setSizeByte(sftpFile.getSize());
|
||||
file.setSize(sftpFile.getSize());
|
||||
file.setPermission(sftpFile.getPermission());
|
||||
file.setUid(sftpFile.getUid());
|
||||
file.setGid(sftpFile.getGid());
|
||||
|
||||
@@ -135,4 +135,24 @@ export function permission10toString(permission: number) {
|
||||
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;
|
||||
|
||||
@@ -68,7 +68,7 @@
|
||||
</span>
|
||||
</a-tooltip>
|
||||
<!-- 编辑内容 -->
|
||||
<a-tooltip v-if="canEditable(record.sizeByte, record.attr)"
|
||||
<a-tooltip v-if="canEditable(record.size, record.attr)"
|
||||
position="top"
|
||||
:mini="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;
|
||||
// 非文件夹和链接文件 并且文件小于 配置大小(MB) 可以编辑
|
||||
return FILE_TYPE.DIRECTORY.value !== typeValue
|
||||
&& FILE_TYPE.LINK_FILE.value !== typeValue
|
||||
&& sizeByte <= previewSize * 1024 * 1024;
|
||||
&& size <= previewSize * 1024 * 1024;
|
||||
};
|
||||
|
||||
// 点击文件名称
|
||||
|
||||
@@ -76,11 +76,11 @@
|
||||
</script>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import type { SftpUploadItem } from '../../types/terminal.type';
|
||||
import useVisible from '@/hooks/visible';
|
||||
import { ref } from 'vue';
|
||||
import { useTerminalStore } from '@/store';
|
||||
import { Message } from '@arco-design/web-vue';
|
||||
import useVisible from '@/hooks/visible';
|
||||
import { TransferStatus, TransferType } from '../../types/terminal.const';
|
||||
|
||||
const { visible, setVisible } = useVisible();
|
||||
const { transferManager } = useTerminalStore();
|
||||
@@ -106,10 +106,15 @@
|
||||
// 添加到上传列表
|
||||
const files = fileList.value.map(s => {
|
||||
return {
|
||||
type: TransferType.UPLOAD,
|
||||
hostId: hostId.value,
|
||||
targetPath: parentPath.value + '/' + (s.file.webkitRelativePath || s.file.name),
|
||||
file: s.file as File
|
||||
} as SftpUploadItem;
|
||||
name: s.file.webkitRelativePath || s.file.name,
|
||||
currentSize: 0,
|
||||
totalSize: s.file.size,
|
||||
status: TransferStatus.WAITING,
|
||||
parentPath: parentPath.value,
|
||||
file: s.file
|
||||
};
|
||||
});
|
||||
transferManager.addUpload(files);
|
||||
Message.success('已开始上传, 点击右侧传输列表查看进度');
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { TableColumnData } from '@arco-design/web-vue/es/table/interface';
|
||||
import { getFileSize } from '@/utils/file';
|
||||
|
||||
// 表格列
|
||||
const columns = [
|
||||
@@ -17,12 +18,15 @@ const columns = [
|
||||
}
|
||||
}, {
|
||||
title: '大小',
|
||||
dataIndex: 'sizeByte',
|
||||
dataIndex: 'size',
|
||||
slotName: 'size',
|
||||
ellipsis: true,
|
||||
sortable: {
|
||||
sortDirections: ['ascend', 'descend'],
|
||||
},
|
||||
render: ({ record }) => {
|
||||
return getFileSize(record.size);
|
||||
},
|
||||
}, {
|
||||
title: '属性',
|
||||
dataIndex: 'attr',
|
||||
|
||||
@@ -6,7 +6,71 @@
|
||||
:unmount-on-close="false"
|
||||
:footer="false">
|
||||
<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-drawer>
|
||||
</template>
|
||||
@@ -21,6 +85,8 @@
|
||||
import useLoading from '@/hooks/loading';
|
||||
import useVisible from '@/hooks/visible';
|
||||
import { useTerminalStore } from '@/store';
|
||||
import { getFileSize } from '@/utils/file';
|
||||
import { TransferStatus } from '../../types/terminal.const';
|
||||
|
||||
const { transferManager } = useTerminalStore();
|
||||
const { visible, setVisible } = useVisible();
|
||||
@@ -46,12 +112,53 @@
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.form-container {
|
||||
padding: 12px;
|
||||
}
|
||||
@item-left-width: 42px;
|
||||
@item-right-width: 42px;
|
||||
@item-center-width: 388px - @item-left-width - @item-right-width;
|
||||
|
||||
.command-editor {
|
||||
height: calc(100vh - 330px);
|
||||
.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;
|
||||
}
|
||||
}
|
||||
|
||||
&-center {
|
||||
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>
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
import type { ISftpTransferManager, SftpUploadItem } from '../types/terminal.type';
|
||||
import type { ISftpTransferManager, SftpTransferItem } from '../types/terminal.type';
|
||||
|
||||
// sftp 传输管理器实现
|
||||
export default class SftpTransferManager implements ISftpTransferManager {
|
||||
|
||||
transferList: Array<SftpUploadItem>;
|
||||
transferList: Array<SftpTransferItem>;
|
||||
|
||||
constructor() {
|
||||
this.transferList = [];
|
||||
}
|
||||
|
||||
// 添加上传文件
|
||||
addUpload(items: Array<SftpUploadItem>): void {
|
||||
addUpload(items: Array<SftpTransferItem>): void {
|
||||
this.transferList.push(...items);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
export const openSshSettingModalKey = Symbol();
|
||||
|
||||
|
||||
@@ -358,8 +358,7 @@ export interface SftpFile {
|
||||
name: string;
|
||||
path: string;
|
||||
suffix: string;
|
||||
size: string;
|
||||
sizeByte: number;
|
||||
size: number;
|
||||
attr: string;
|
||||
isDir: boolean;
|
||||
permission: number;
|
||||
@@ -370,14 +369,19 @@ export interface SftpFile {
|
||||
|
||||
// sftp 传输管理器定义
|
||||
export interface ISftpTransferManager {
|
||||
transferList: Array<SftpUploadItem>;
|
||||
transferList: Array<SftpTransferItem>;
|
||||
// 添加上传文件
|
||||
addUpload: (items: Array<SftpUploadItem>) => void;
|
||||
addUpload: (items: Array<SftpTransferItem>) => void;
|
||||
}
|
||||
|
||||
// sftp 上传文件项
|
||||
export interface SftpUploadItem {
|
||||
export interface SftpTransferItem {
|
||||
type: string;
|
||||
hostId: number;
|
||||
targetPath: string;
|
||||
name: string;
|
||||
parentPath: string;
|
||||
currentSize: number,
|
||||
totalSize: number;
|
||||
status: string;
|
||||
file: File;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user