🔨 文件上传.
This commit is contained in:
@@ -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;
|
||||||
|
|||||||
@@ -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());
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
// 点击文件名称
|
// 点击文件名称
|
||||||
|
|||||||
@@ -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('已开始上传, 点击右侧传输列表查看进度');
|
||||||
|
|||||||
@@ -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',
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
.command-editor {
|
.transfer-item {
|
||||||
height: calc(100vh - 330px);
|
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>
|
</style>
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user