🔨 批量上传.
This commit is contained in:
@@ -40,7 +40,7 @@ import java.util.List;
|
|||||||
@SuppressWarnings({"ELValidationInJSP", "SpringElInspection"})
|
@SuppressWarnings({"ELValidationInJSP", "SpringElInspection"})
|
||||||
public class UploadTaskController {
|
public class UploadTaskController {
|
||||||
|
|
||||||
// TODO 测试空文件上传 0B 取消怎么那么慢 是不是删除也慢 异步cancel cancel 需要设置子元素为 cancel
|
// TODO 前端日志 测试删除慢吗
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private UploadTaskService uploadTaskService;
|
private UploadTaskService uploadTaskService;
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import lombok.Data;
|
|||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 上传任务 视图响应对象
|
* 上传任务 视图响应对象
|
||||||
@@ -31,7 +30,4 @@ public class UploadTaskCreateVO implements Serializable {
|
|||||||
@Schema(description = "上传 token")
|
@Schema(description = "上传 token")
|
||||||
private String token;
|
private String token;
|
||||||
|
|
||||||
@Schema(description = "主机")
|
|
||||||
private List<HostBaseVO> hosts;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,6 +43,9 @@ public class UploadTaskFileVO implements Serializable {
|
|||||||
@Schema(description = "文件大小")
|
@Schema(description = "文件大小")
|
||||||
private Long fileSize;
|
private Long fileSize;
|
||||||
|
|
||||||
|
@Schema(description = "额外信息")
|
||||||
|
private String extraInfo;
|
||||||
|
|
||||||
@Schema(description = "状态")
|
@Schema(description = "状态")
|
||||||
private String status;
|
private String status;
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
package com.orion.ops.module.asset.entity.vo;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 上传任务主机 视图响应对象
|
||||||
|
*
|
||||||
|
* @author Jiahang Li
|
||||||
|
* @version 1.0.7
|
||||||
|
* @since 2024-5-8 10:31
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
@Schema(name = "UploadTaskHostVO", description = "上传任务主机 视图响应对象")
|
||||||
|
public class UploadTaskHostVO implements Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@Schema(description = "id")
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@Schema(description = "主机名称")
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@Schema(description = "主机编码")
|
||||||
|
private String code;
|
||||||
|
|
||||||
|
@Schema(description = "主机地址")
|
||||||
|
private String address;
|
||||||
|
|
||||||
|
@Schema(description = "上传文件")
|
||||||
|
private List<UploadTaskFileVO> files;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -56,7 +56,7 @@ public class UploadTaskVO implements Serializable {
|
|||||||
@Schema(description = "创建时间")
|
@Schema(description = "创建时间")
|
||||||
private Date createTime;
|
private Date createTime;
|
||||||
|
|
||||||
@Schema(description = "上传文件")
|
@Schema(description = "上传主机及文件")
|
||||||
private List<UploadTaskFileVO> files;
|
private List<UploadTaskHostVO> hosts;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -128,7 +128,6 @@ public class SftpSession extends TerminalSession implements ISftpSession {
|
|||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw Exceptions.ioRuntime(e);
|
throw Exceptions.ioRuntime(e);
|
||||||
} finally {
|
} finally {
|
||||||
// TODO Test
|
|
||||||
// 关闭 inputStream 可能会被阻塞 ???...??? 只能关闭 executor
|
// 关闭 inputStream 可能会被阻塞 ???...??? 只能关闭 executor
|
||||||
Streams.close(this.executor);
|
Streams.close(this.executor);
|
||||||
this.connect();
|
this.connect();
|
||||||
|
|||||||
@@ -141,6 +141,9 @@ public class FileUploadTask implements IFileUploadTask {
|
|||||||
.current(0L)
|
.current(0L)
|
||||||
.build())
|
.build())
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
|
if (files.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
// 添加到上传器
|
// 添加到上传器
|
||||||
uploaderList.add(new FileUploader(id, k, files));
|
uploaderList.add(new FileUploader(id, k, files));
|
||||||
});
|
});
|
||||||
@@ -150,6 +153,10 @@ public class FileUploadTask implements IFileUploadTask {
|
|||||||
* 执行上传
|
* 执行上传
|
||||||
*/
|
*/
|
||||||
private void runUpload() throws Exception {
|
private void runUpload() throws Exception {
|
||||||
|
if (uploaderList.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 执行
|
||||||
if (uploaderList.size() == 1) {
|
if (uploaderList.size() == 1) {
|
||||||
// 单个主机直接执行
|
// 单个主机直接执行
|
||||||
IFileUploader handler = uploaderList.get(0);
|
IFileUploader handler = uploaderList.get(0);
|
||||||
|
|||||||
@@ -141,7 +141,6 @@ public class FileUploader implements IFileUploader {
|
|||||||
int read;
|
int read;
|
||||||
while ((read = inputStream.read(buffer)) != -1) {
|
while ((read = inputStream.read(buffer)) != -1) {
|
||||||
outputStream.write(buffer, 0, read);
|
outputStream.write(buffer, 0, read);
|
||||||
// todo test
|
|
||||||
file.setCurrent(file.getCurrent() + read);
|
file.setCurrent(file.getCurrent() + read);
|
||||||
}
|
}
|
||||||
outputStream.flush();
|
outputStream.flush();
|
||||||
|
|||||||
@@ -32,10 +32,7 @@ import com.orion.ops.module.asset.entity.request.upload.UploadTaskCreateRequest;
|
|||||||
import com.orion.ops.module.asset.entity.request.upload.UploadTaskFileRequest;
|
import com.orion.ops.module.asset.entity.request.upload.UploadTaskFileRequest;
|
||||||
import com.orion.ops.module.asset.entity.request.upload.UploadTaskQueryRequest;
|
import com.orion.ops.module.asset.entity.request.upload.UploadTaskQueryRequest;
|
||||||
import com.orion.ops.module.asset.entity.request.upload.UploadTaskRequest;
|
import com.orion.ops.module.asset.entity.request.upload.UploadTaskRequest;
|
||||||
import com.orion.ops.module.asset.entity.vo.HostBaseVO;
|
import com.orion.ops.module.asset.entity.vo.*;
|
||||||
import com.orion.ops.module.asset.entity.vo.UploadTaskCreateVO;
|
|
||||||
import com.orion.ops.module.asset.entity.vo.UploadTaskFileVO;
|
|
||||||
import com.orion.ops.module.asset.entity.vo.UploadTaskVO;
|
|
||||||
import com.orion.ops.module.asset.enums.HostConfigTypeEnum;
|
import com.orion.ops.module.asset.enums.HostConfigTypeEnum;
|
||||||
import com.orion.ops.module.asset.enums.UploadTaskFileStatusEnum;
|
import com.orion.ops.module.asset.enums.UploadTaskFileStatusEnum;
|
||||||
import com.orion.ops.module.asset.enums.UploadTaskStatusEnum;
|
import com.orion.ops.module.asset.enums.UploadTaskStatusEnum;
|
||||||
@@ -147,7 +144,6 @@ public class UploadTaskServiceImpl implements UploadTaskService {
|
|||||||
return UploadTaskCreateVO.builder()
|
return UploadTaskCreateVO.builder()
|
||||||
.id(id)
|
.id(id)
|
||||||
.token(token)
|
.token(token)
|
||||||
.hosts(hosts)
|
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -158,11 +154,12 @@ public class UploadTaskServiceImpl implements UploadTaskService {
|
|||||||
Valid.notNull(record, ErrorMessage.DATA_ABSENT);
|
Valid.notNull(record, ErrorMessage.DATA_ABSENT);
|
||||||
// 查询任务文件
|
// 查询任务文件
|
||||||
List<UploadTaskFileVO> files = uploadTaskFileService.getFileByTaskId(id);
|
List<UploadTaskFileVO> files = uploadTaskFileService.getFileByTaskId(id);
|
||||||
// 计算传输进度
|
|
||||||
this.computeUploadProgress(id, files);
|
|
||||||
// 返回
|
// 返回
|
||||||
UploadTaskVO uploadTask = UploadTaskConvert.MAPPER.to(record);
|
UploadTaskVO uploadTask = UploadTaskConvert.MAPPER.to(record);
|
||||||
uploadTask.setFiles(files);
|
// 计算传输进度
|
||||||
|
this.computeUploadProgress(id, files);
|
||||||
|
// 设置任务文件
|
||||||
|
this.setTaskFiles(uploadTask, files);
|
||||||
return uploadTask;
|
return uploadTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -208,8 +205,9 @@ public class UploadTaskServiceImpl implements UploadTaskService {
|
|||||||
} else {
|
} else {
|
||||||
// 计算进度
|
// 计算进度
|
||||||
this.computeUploadProgress(id, files);
|
this.computeUploadProgress(id, files);
|
||||||
|
// 设置任务文件
|
||||||
}
|
}
|
||||||
task.setFiles(files);
|
this.setTaskFiles(task, files);
|
||||||
}
|
}
|
||||||
return tasks;
|
return tasks;
|
||||||
}
|
}
|
||||||
@@ -299,8 +297,6 @@ public class UploadTaskServiceImpl implements UploadTaskService {
|
|||||||
.map(localFileClient::getReturnPath)
|
.map(localFileClient::getReturnPath)
|
||||||
.map(localFileClient::getAbsolutePath)
|
.map(localFileClient::getAbsolutePath)
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
// TODO test
|
|
||||||
paths.forEach(System.out::println);
|
|
||||||
// 删除文件
|
// 删除文件
|
||||||
paths.forEach(Files1::delete);
|
paths.forEach(Files1::delete);
|
||||||
}
|
}
|
||||||
@@ -393,7 +389,7 @@ public class UploadTaskServiceImpl implements UploadTaskService {
|
|||||||
uploadFile.setStatus(UploadTaskFileStatusEnum.CANCELED.name());
|
uploadFile.setStatus(UploadTaskFileStatusEnum.CANCELED.name());
|
||||||
uploadFile.setEndTime(new Date());
|
uploadFile.setEndTime(new Date());
|
||||||
LambdaQueryWrapper<UploadTaskFileDO> updateFileQuery = uploadTaskFileDAO.wrapper()
|
LambdaQueryWrapper<UploadTaskFileDO> updateFileQuery = uploadTaskFileDAO.wrapper()
|
||||||
.in(UploadTaskFileDO::getId, updateIdList)
|
.in(UploadTaskFileDO::getTaskId, updateIdList)
|
||||||
.in(UploadTaskFileDO::getStatus,
|
.in(UploadTaskFileDO::getStatus,
|
||||||
UploadTaskFileStatusEnum.WAITING.name(),
|
UploadTaskFileStatusEnum.WAITING.name(),
|
||||||
UploadTaskFileStatusEnum.UPLOADING.name());
|
UploadTaskFileStatusEnum.UPLOADING.name());
|
||||||
@@ -446,11 +442,34 @@ public class UploadTaskServiceImpl implements UploadTaskService {
|
|||||||
} else if (UploadTaskFileStatusEnum.FINISHED.name().equals(status)) {
|
} else if (UploadTaskFileStatusEnum.FINISHED.name().equals(status)) {
|
||||||
file.setCurrent(file.getFileSize());
|
file.setCurrent(file.getFileSize());
|
||||||
} else if (UploadTaskFileStatusEnum.FAILED.name().equals(status)) {
|
} else if (UploadTaskFileStatusEnum.FAILED.name().equals(status)) {
|
||||||
file.setCurrent(0L);
|
file.setCurrent(file.getFileSize());
|
||||||
} else if (UploadTaskFileStatusEnum.CANCELED.name().equals(status)) {
|
} else if (UploadTaskFileStatusEnum.CANCELED.name().equals(status)) {
|
||||||
file.setCurrent(0L);
|
file.setCurrent(file.getFileSize());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置任务文件
|
||||||
|
*
|
||||||
|
* @param task task
|
||||||
|
* @param files files
|
||||||
|
*/
|
||||||
|
private void setTaskFiles(UploadTaskVO task, List<UploadTaskFileVO> files) {
|
||||||
|
Map<Long, List<UploadTaskFileVO>> hostFiles = files.stream()
|
||||||
|
.collect(Collectors.groupingBy(UploadTaskFileVO::getHostId));
|
||||||
|
List<UploadTaskHostVO> hosts = JSON.parseObject(task.getExtraInfo(), UploadTaskExtraDTO.class)
|
||||||
|
.getHosts()
|
||||||
|
.stream()
|
||||||
|
.map(s -> UploadTaskHostVO.builder()
|
||||||
|
.id(s.getId())
|
||||||
|
.code(s.getCode())
|
||||||
|
.name(s.getName())
|
||||||
|
.address(s.getAddress())
|
||||||
|
.files(hostFiles.get(s.getId()))
|
||||||
|
.build())
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
task.setHosts(hosts);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import type { DataGrid, Pagination } from '@/types/global';
|
import type { DataGrid, Pagination } from '@/types/global';
|
||||||
import type { HostQueryResponse } from '@/api/asset/host';
|
|
||||||
import type { TableData } from '@arco-design/web-vue/es/table/interface';
|
import type { TableData } from '@arco-design/web-vue/es/table/interface';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import qs from 'query-string';
|
import qs from 'query-string';
|
||||||
@@ -29,7 +28,6 @@ export interface UploadTaskFileCreateRequest {
|
|||||||
export interface UploadTaskCreateResponse {
|
export interface UploadTaskCreateResponse {
|
||||||
id: number;
|
id: number;
|
||||||
token: string;
|
token: string;
|
||||||
hosts: Array<HostQueryResponse>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -58,13 +56,24 @@ export interface UploadTaskQueryResponse extends TableData {
|
|||||||
startTime: number;
|
startTime: number;
|
||||||
endTime: number;
|
endTime: number;
|
||||||
createTime: number;
|
createTime: number;
|
||||||
files: Array<UploadTaskFileQueryResponse>;
|
hosts: Array<UploadTaskHost>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 上传任务文件查询响应
|
* 上传任务主机响应
|
||||||
*/
|
*/
|
||||||
export interface UploadTaskFileQueryResponse {
|
export interface UploadTaskHost {
|
||||||
|
id: number;
|
||||||
|
code: string;
|
||||||
|
name: string;
|
||||||
|
address: string;
|
||||||
|
files: Array<UploadTaskFile>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 上传任务文件响应
|
||||||
|
*/
|
||||||
|
export interface UploadTaskFile {
|
||||||
id: number;
|
id: number;
|
||||||
taskId: number;
|
taskId: number;
|
||||||
hostId: number;
|
hostId: number;
|
||||||
|
|||||||
@@ -4,10 +4,10 @@
|
|||||||
<div class="panel-header">
|
<div class="panel-header">
|
||||||
<h3>文件列表</h3>
|
<h3>文件列表</h3>
|
||||||
<!-- 操作 -->
|
<!-- 操作 -->
|
||||||
<a-button-group size="small" :disabled="startStatus">
|
<a-button-group size="mini" :disabled="startStatus">
|
||||||
<a-button @click="clear">清空</a-button>
|
<a-button @click="clear">清空</a-button>
|
||||||
<!-- 选择文件 -->
|
<!-- 选择文件 -->
|
||||||
<a-upload v-model:file-list="fileList"
|
<a-upload v-model:file-list="files"
|
||||||
:auto-upload="false"
|
:auto-upload="false"
|
||||||
:show-file-list="false"
|
:show-file-list="false"
|
||||||
:multiple="true">
|
:multiple="true">
|
||||||
@@ -16,7 +16,7 @@
|
|||||||
</template>
|
</template>
|
||||||
</a-upload>
|
</a-upload>
|
||||||
<!-- 选择文件夹 -->
|
<!-- 选择文件夹 -->
|
||||||
<a-upload v-model:file-list="fileList"
|
<a-upload v-model:file-list="files"
|
||||||
:auto-upload="false"
|
:auto-upload="false"
|
||||||
:show-file-list="false"
|
:show-file-list="false"
|
||||||
:directory="true">
|
:directory="true">
|
||||||
@@ -27,34 +27,36 @@
|
|||||||
</a-button-group>
|
</a-button-group>
|
||||||
</div>
|
</div>
|
||||||
<!-- 文件列表 -->
|
<!-- 文件列表 -->
|
||||||
<div v-if="fileList.length" class="files-container">
|
<div v-if="files.length" class="files-container">
|
||||||
<a-upload class="files-wrapper"
|
<a-scrollbar style="overflow-y: auto; height: 100%;">
|
||||||
:class="[ startStatus ? 'uploading-files-wrapper' : 'waiting-files-wrapper' ]"
|
<a-upload class="files-wrapper"
|
||||||
v-model:file-list="fileList"
|
:class="[ startStatus ? 'uploading-files-wrapper' : 'waiting-files-wrapper' ]"
|
||||||
:auto-upload="false"
|
v-model:file-list="files"
|
||||||
:show-cancel-button="false"
|
:auto-upload="false"
|
||||||
:show-retry-button="false"
|
:show-cancel-button="false"
|
||||||
:show-remove-button="!startStatus"
|
:show-retry-button="false"
|
||||||
:show-file-list="true">
|
:show-remove-button="!startStatus"
|
||||||
<template #upload-button />
|
:show-file-list="true">
|
||||||
<template #file-name="{ fileItem }">
|
<template #upload-button />
|
||||||
<div class="file-name-wrapper">
|
<template #file-name="{ fileItem }">
|
||||||
<!-- 文件名称 -->
|
<div class="file-name-wrapper">
|
||||||
<a-tooltip position="left"
|
|
||||||
:mini="true"
|
|
||||||
:content="fileItem.file.webkitRelativePath || fileItem.file.name">
|
|
||||||
<!-- 文件名称 -->
|
<!-- 文件名称 -->
|
||||||
<span class="file-name text-ellipsis">
|
<a-tooltip position="left"
|
||||||
|
:mini="true"
|
||||||
|
:content="fileItem.file.webkitRelativePath || fileItem.file.name">
|
||||||
|
<!-- 文件名称 -->
|
||||||
|
<span class="file-name text-ellipsis">
|
||||||
{{ fileItem.file.webkitRelativePath || fileItem.file.name }}
|
{{ fileItem.file.webkitRelativePath || fileItem.file.name }}
|
||||||
</span>
|
</span>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
<!-- 文件大小 -->
|
<!-- 文件大小 -->
|
||||||
<span class="file-size span-blue">
|
<span class="file-size span-blue">
|
||||||
{{ getFileSize(fileItem.file.size) }}
|
{{ getFileSize(fileItem.file.size) }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</a-upload>
|
</a-upload>
|
||||||
|
</a-scrollbar>
|
||||||
</div>
|
</div>
|
||||||
<!-- 未选择文件 -->
|
<!-- 未选择文件 -->
|
||||||
<a-result v-else
|
<a-result v-else
|
||||||
@@ -72,38 +74,35 @@
|
|||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import type { FileItem } from '@arco-design/web-vue';
|
import type { FileItem } from '@arco-design/web-vue';
|
||||||
import type { UploadTaskFileCreateRequest } from '@/api/exec/upload-task';
|
|
||||||
import type { IFileUploader } from '@/components/system/uploader/const';
|
import type { IFileUploader } from '@/components/system/uploader/const';
|
||||||
import { onUnmounted, ref } from 'vue';
|
import { computed, onUnmounted, ref } from 'vue';
|
||||||
import { getFileSize } from '@/utils/file';
|
import { getFileSize } from '@/utils/file';
|
||||||
import FileUploader from '@/components/system/uploader/file-uploader';
|
import FileUploader from '@/components/system/uploader/file-uploader';
|
||||||
|
|
||||||
const emits = defineEmits(['end', 'error']);
|
const emits = defineEmits(['update:fileList', 'end', 'error', 'clearFile']);
|
||||||
|
const props = defineProps<{
|
||||||
|
fileList: Array<FileItem>;
|
||||||
|
}>();
|
||||||
|
|
||||||
const startStatus = ref(false);
|
const startStatus = ref(false);
|
||||||
const fileList = ref<FileItem[]>([]);
|
|
||||||
const uploader = ref<IFileUploader>();
|
const uploader = ref<IFileUploader>();
|
||||||
|
const files = computed<Array<FileItem>>({
|
||||||
// 获取上传的文件
|
get() {
|
||||||
const getFiles = (): Array<UploadTaskFileCreateRequest> => {
|
return props.fileList;
|
||||||
return fileList.value
|
},
|
||||||
.map(s => {
|
set(e) {
|
||||||
return {
|
emits('update:fileList', e);
|
||||||
fileId: s.uid,
|
}
|
||||||
filePath: s.file?.webkitRelativePath || s.file?.name,
|
});
|
||||||
fileSize: s.file?.size,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// 开始上传
|
// 开始上传
|
||||||
const startUpload = async (token: string) => {
|
const startUpload = async (token: string) => {
|
||||||
// 修改状态
|
// 修改状态
|
||||||
startStatus.value = true;
|
startStatus.value = true;
|
||||||
fileList.value.forEach(s => s.status = 'uploading');
|
props.fileList.forEach(s => s.status = 'uploading');
|
||||||
// 开始上传
|
// 开始上传
|
||||||
try {
|
try {
|
||||||
uploader.value = new FileUploader(token, fileList.value);
|
uploader.value = new FileUploader(token, props.fileList);
|
||||||
uploader.value?.setHook(() => {
|
uploader.value?.setHook(() => {
|
||||||
emits('end');
|
emits('end');
|
||||||
});
|
});
|
||||||
@@ -115,8 +114,8 @@
|
|||||||
|
|
||||||
// 清空
|
// 清空
|
||||||
const clear = () => {
|
const clear = () => {
|
||||||
fileList.value = [];
|
|
||||||
startStatus.value = false;
|
startStatus.value = false;
|
||||||
|
emits('clearFile');
|
||||||
};
|
};
|
||||||
|
|
||||||
// 关闭
|
// 关闭
|
||||||
@@ -125,7 +124,7 @@
|
|||||||
uploader.value?.close();
|
uploader.value?.close();
|
||||||
};
|
};
|
||||||
|
|
||||||
defineExpose({ getFiles, startUpload, close });
|
defineExpose({ startUpload, close });
|
||||||
|
|
||||||
// 卸载时关闭
|
// 卸载时关闭
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
@@ -171,7 +170,6 @@
|
|||||||
:deep(.arco-upload-wrapper) {
|
:deep(.arco-upload-wrapper) {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
overflow-y: auto;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.arco-upload) {
|
:deep(.arco-upload) {
|
||||||
@@ -181,8 +179,6 @@
|
|||||||
:deep(.arco-upload-list) {
|
:deep(.arco-upload-list) {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
max-height: 100%;
|
max-height: 100%;
|
||||||
overflow-x: hidden;
|
|
||||||
overflow-y: auto;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.arco-upload-list-item-error) {
|
:deep(.arco-upload-list-item-error) {
|
||||||
@@ -222,4 +218,10 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
:deep(.arco-scrollbar) {
|
||||||
|
position: absolute;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -4,21 +4,21 @@
|
|||||||
<div class="panel-header">
|
<div class="panel-header">
|
||||||
<h3>批量上传</h3>
|
<h3>批量上传</h3>
|
||||||
<!-- 操作 -->
|
<!-- 操作 -->
|
||||||
<a-button-group size="small">
|
<a-button-group size="mini">
|
||||||
<!-- 重置 -->
|
<!-- 重置 -->
|
||||||
<a-button v-if="status.value !== UploadTaskStatus.REQUESTING.value"
|
<a-button v-if="status.value === UploadTaskStatus.WAITING.value"
|
||||||
@click="emits('clear')">
|
@click="emits('clear')">
|
||||||
重置
|
重置
|
||||||
</a-button>
|
</a-button>
|
||||||
<!-- 取消上传 -->
|
<!-- 取消上传 -->
|
||||||
<a-button v-if="status.value === UploadTaskStatus.REQUESTING.value
|
<a-button v-if="status.value === UploadTaskStatus.REQUESTING.value"
|
||||||
|| status.value === UploadTaskStatus.UPLOADING.value"
|
type="primary"
|
||||||
@click="emits('cancel')">
|
status="warning"
|
||||||
|
@click="emits('abort')">
|
||||||
取消上传
|
取消上传
|
||||||
</a-button>
|
</a-button>
|
||||||
<!-- 开始上传 -->
|
<!-- 开始上传 -->
|
||||||
<a-button v-if="status.value !== UploadTaskStatus.REQUESTING.value
|
<a-button v-if="status.value === UploadTaskStatus.WAITING.value"
|
||||||
&& status.value !== UploadTaskStatus.UPLOADING.value"
|
|
||||||
type="primary"
|
type="primary"
|
||||||
@click="submit">
|
@click="submit">
|
||||||
开始上传
|
开始上传
|
||||||
@@ -73,7 +73,7 @@
|
|||||||
import formRules from '../types/form.rules';
|
import formRules from '../types/form.rules';
|
||||||
import { UploadTaskStatus } from '../types/const';
|
import { UploadTaskStatus } from '../types/const';
|
||||||
|
|
||||||
const emits = defineEmits(['upload', 'openHost', 'cancel', 'clear']);
|
const emits = defineEmits(['upload', 'openHost', 'abort', 'clear']);
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
status: UploadTaskStatusType;
|
status: UploadTaskStatusType;
|
||||||
formModel: UploadTaskCreateRequest;
|
formModel: UploadTaskCreateRequest;
|
||||||
|
|||||||
@@ -0,0 +1,174 @@
|
|||||||
|
<template>
|
||||||
|
<div class="container">
|
||||||
|
<!-- 表头 -->
|
||||||
|
<div class="panel-header">
|
||||||
|
<h3>上传主机</h3>
|
||||||
|
<!-- 操作 -->
|
||||||
|
<a-button-group size="mini">
|
||||||
|
<!-- 返回 -->
|
||||||
|
<a-button @click="emits('back')">返回</a-button>
|
||||||
|
<!-- 取消上传 -->
|
||||||
|
<a-button type="primary"
|
||||||
|
status="warning"
|
||||||
|
@click="emits('cancel')">
|
||||||
|
取消上传
|
||||||
|
</a-button>
|
||||||
|
</a-button-group>
|
||||||
|
</div>
|
||||||
|
<!-- 主机列表 -->
|
||||||
|
<div class="wrapper">
|
||||||
|
<a-scrollbar style="overflow-y: auto; height: 100%;">
|
||||||
|
<!-- 主机 -->
|
||||||
|
<div v-for="host in task.hosts"
|
||||||
|
class="host-item"
|
||||||
|
:class="[ selectedHost === host.id ? 'host-item-active' : '']"
|
||||||
|
@click="changeSelectedHost(host.id)">
|
||||||
|
<!-- 主机信息 -->
|
||||||
|
<div class="host-item-host">
|
||||||
|
<!-- 主机名称 -->
|
||||||
|
<div class="host-item-name text-ellipsis" :title="host.name">
|
||||||
|
{{ host.name }}
|
||||||
|
</div>
|
||||||
|
<!-- 主机地址 -->
|
||||||
|
<div class="host-item-address text-ellipsis" :title="host.address">
|
||||||
|
{{ host.address }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 主机状态 -->
|
||||||
|
<a-space class="host-item-status" direction="vertical">
|
||||||
|
<!-- 未完成 -->
|
||||||
|
<a-tag class="host-item-status-tag" color="#52C41A">
|
||||||
|
{{ host.files.length - getFinishCount(host.files) }}
|
||||||
|
<template #icon>
|
||||||
|
<icon-clock-circle class="host-item-status-icon" />
|
||||||
|
</template>
|
||||||
|
</a-tag>
|
||||||
|
<!-- 已完成 -->
|
||||||
|
<a-tag class="host-item-status-tag" color="#1890FF">
|
||||||
|
{{ getFinishCount(host.files) }}
|
||||||
|
<template #icon>
|
||||||
|
<icon-check-circle class="host-item-status-icon" />
|
||||||
|
</template>
|
||||||
|
</a-tag>
|
||||||
|
</a-space>
|
||||||
|
</div>
|
||||||
|
</a-scrollbar>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
export default {
|
||||||
|
name: 'batchUploadHosts'
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import type { UploadTaskQueryResponse } from '@/api/exec/upload-task';
|
||||||
|
import type { UploadTaskFile } from '@/api/exec/upload-task';
|
||||||
|
import { UploadTaskFileStatus } from '../types/const';
|
||||||
|
|
||||||
|
const emits = defineEmits(['update:selectedHost', 'back', 'cancel']);
|
||||||
|
const props = defineProps<{
|
||||||
|
selectedHost: number;
|
||||||
|
task: UploadTaskQueryResponse;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
// 修改选中的主机
|
||||||
|
const changeSelectedHost = (id: number) => {
|
||||||
|
emits('update:selectedHost', id);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 获取已完成数量
|
||||||
|
const getFinishCount = (files: Array<UploadTaskFile>) => {
|
||||||
|
return files.filter(s => s.status === UploadTaskFileStatus.FINISHED
|
||||||
|
|| s.status === UploadTaskFileStatus.CANCELED
|
||||||
|
|| s.status === UploadTaskFileStatus.FAILED).length;
|
||||||
|
};
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
|
||||||
|
.wrapper {
|
||||||
|
width: 100%;
|
||||||
|
height: calc(100% - 36px);
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
.host-item {
|
||||||
|
padding: 12px;
|
||||||
|
border-radius: 6px;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
position: relative;
|
||||||
|
background: var(--color-fill-1);
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: var(--color-fill-2);
|
||||||
|
}
|
||||||
|
|
||||||
|
&-host {
|
||||||
|
width: calc(100% - 64px);
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-status {
|
||||||
|
user-select: none;
|
||||||
|
|
||||||
|
&-tag {
|
||||||
|
max-width: 64px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-icon {
|
||||||
|
color: #FFFFFF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&-name {
|
||||||
|
width: 100%;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
font-size: 14px;
|
||||||
|
color: var(--color-text-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
&-address {
|
||||||
|
width: 100%;
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--color-text-3);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.host-item-active {
|
||||||
|
background: var(--color-fill-2) !important;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
width: 3px;
|
||||||
|
height: 100%;
|
||||||
|
border-radius: 4px 6px 6px 4px;
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 1px;
|
||||||
|
background: rgb(var(--arcoblue-6));
|
||||||
|
content: '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.arco-scrollbar) {
|
||||||
|
position: absolute;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,105 @@
|
|||||||
|
<template>
|
||||||
|
<div class="container">
|
||||||
|
<!-- 表头 -->
|
||||||
|
<div class="panel-header">
|
||||||
|
<h3>传输列表</h3>
|
||||||
|
</div>
|
||||||
|
<div class="wrapper">
|
||||||
|
<a-scrollbar style="overflow-y: auto; height: 100%;">
|
||||||
|
<!-- 主机 -->
|
||||||
|
<div v-for="file in files" class="file-item">
|
||||||
|
<!-- 图标 -->
|
||||||
|
<div class="file-item-icon span-blue">
|
||||||
|
<icon-file />
|
||||||
|
</div>
|
||||||
|
<!-- 文件路径 -->
|
||||||
|
<div class="file-item-path text-ellipsis" :title="file.filePath">
|
||||||
|
{{ file.filePath }}
|
||||||
|
</div>
|
||||||
|
<!-- 进度 -->
|
||||||
|
<div class="file-item-progress">
|
||||||
|
<a-progress type="circle"
|
||||||
|
size="mini"
|
||||||
|
:status="getDictValue(fileStatusKey, file.status, 'status') as any"
|
||||||
|
:percent="file.current / file.fileSize" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a-scrollbar>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
export default {
|
||||||
|
name: 'batchUploadProgress'
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import type { UploadTaskFile } from '@/api/exec/upload-task';
|
||||||
|
import { fileStatusKey } from '../types/const';
|
||||||
|
import { useDictStore } from '@/store';
|
||||||
|
|
||||||
|
const emits = defineEmits(['update:selectedHost']);
|
||||||
|
const props = defineProps<{
|
||||||
|
files: Array<UploadTaskFile>;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const { getDictValue } = useDictStore();
|
||||||
|
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
@icon-width: 24px;
|
||||||
|
@progress-width: 24px;
|
||||||
|
|
||||||
|
.wrapper {
|
||||||
|
width: 100%;
|
||||||
|
height: calc(100% - 36px);
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
.file-item {
|
||||||
|
padding: 12px;
|
||||||
|
border-radius: 6px;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
position: relative;
|
||||||
|
background: var(--color-fill-1);
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: var(--color-fill-2);
|
||||||
|
}
|
||||||
|
|
||||||
|
&-icon {
|
||||||
|
width: @icon-width;
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-path {
|
||||||
|
width: calc(100% - @icon-width - @progress-width);
|
||||||
|
font-size: 14px;
|
||||||
|
color: var(--color-text-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
&-progress {
|
||||||
|
width: @progress-width;
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.arco-scrollbar) {
|
||||||
|
position: absolute;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
@@ -1,21 +1,40 @@
|
|||||||
<template>
|
<template>
|
||||||
<a-spin class="panel-container full" :loading="loading">
|
<a-spin class="panel-container full" :loading="loading">
|
||||||
<!-- 上传步骤 -->
|
<!-- 上传步骤 -->
|
||||||
<batch-upload-step class="panel-item step-panel-container"
|
<batch-upload-step class="panel-item first-panel-container"
|
||||||
:status="status" />
|
:status="status" />
|
||||||
<!-- 上传表单 -->
|
<!-- 上传表单 -->
|
||||||
<batch-upload-form class="panel-item form-panel-container"
|
<batch-upload-form v-if="status.formPanel"
|
||||||
|
class="panel-item center-panel-container"
|
||||||
:form-model="formModel"
|
:form-model="formModel"
|
||||||
:status="status"
|
:status="status"
|
||||||
@upload="doCreateUploadTask"
|
@upload="doCreateUploadTask"
|
||||||
@cancel="doCancelUploadTask"
|
@abort="abortUploadRequest"
|
||||||
@open-host="openHostModal"
|
@open-host="openHostModal"
|
||||||
@clear="clear" />
|
@clear="clearForm" />
|
||||||
<!-- 上传文件 -->
|
<!-- 上传主机 -->
|
||||||
<batch-upload-files class="panel-item files-panel-container"
|
<batch-upload-hosts v-else
|
||||||
|
class="panel-item center-panel-container"
|
||||||
|
v-model:selected-host="selectedHost"
|
||||||
|
:task="task"
|
||||||
|
@back="backFormPanel"
|
||||||
|
@cancel="doCancelUploadTask" />
|
||||||
|
<!-- 文件列表 -->
|
||||||
|
<batch-upload-files v-if="status.formPanel"
|
||||||
|
v-model:file-list="fileList"
|
||||||
|
class="panel-item last-panel-container"
|
||||||
ref="filesRef"
|
ref="filesRef"
|
||||||
@end="uploadRequestEnd"
|
@end="uploadRequestEnd"
|
||||||
@error="uploadRequestError" />
|
@error="uploadRequestError"
|
||||||
|
@clear-file="clearFile" />
|
||||||
|
<!-- 传输进度 -->
|
||||||
|
<template v-else>
|
||||||
|
<template v-for="host in task.hosts">
|
||||||
|
<batch-upload-progress v-if="host.id === selectedHost"
|
||||||
|
class="panel-item last-panel-container"
|
||||||
|
:files="host.files" />
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
<!-- 主机模态框 -->
|
<!-- 主机模态框 -->
|
||||||
<authorized-host-modal ref="hostModal"
|
<authorized-host-modal ref="hostModal"
|
||||||
@selected="setSelectedHost" />
|
@selected="setSelectedHost" />
|
||||||
@@ -24,21 +43,24 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
export default {
|
export default {
|
||||||
name: 'batchUploadPanel'
|
name: 'uploadPanel'
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import type { UploadTaskCreateRequest } from '@/api/exec/upload-task';
|
import type { FileItem } from '@arco-design/web-vue';
|
||||||
|
import type { UploadTaskCreateRequest, UploadTaskQueryResponse } from '@/api/exec/upload-task';
|
||||||
import type { UploadTaskStatusType } from '../types/const';
|
import type { UploadTaskStatusType } from '../types/const';
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
import { UploadTaskStatus } from '../types/const';
|
import { UploadTaskStatus } from '../types/const';
|
||||||
import { cancelUploadTask, createUploadTask, startUploadTask } from '@/api/exec/upload-task';
|
import { cancelUploadTask, createUploadTask, startUploadTask, getUploadTask } from '@/api/exec/upload-task';
|
||||||
import useLoading from '@/hooks/loading';
|
import useLoading from '@/hooks/loading';
|
||||||
import { Message } from '@arco-design/web-vue';
|
import { Message } from '@arco-design/web-vue';
|
||||||
import BatchUploadStep from './batch-upload-step.vue';
|
import BatchUploadStep from './batch-upload-step.vue';
|
||||||
import BatchUploadForm from './batch-upload-form.vue';
|
import BatchUploadForm from './batch-upload-form.vue';
|
||||||
import BatchUploadFiles from './batch-upload-files.vue';
|
import BatchUploadFiles from './batch-upload-files.vue';
|
||||||
|
import BatchUploadHosts from './batch-upload-hosts.vue';
|
||||||
|
import BatchUploadProgress from './batch-upload-progress.vue';
|
||||||
import AuthorizedHostModal from '@/components/asset/host/authorized-host-modal/index.vue';
|
import AuthorizedHostModal from '@/components/asset/host/authorized-host-modal/index.vue';
|
||||||
|
|
||||||
const defaultForm = (): UploadTaskCreateRequest => {
|
const defaultForm = (): UploadTaskCreateRequest => {
|
||||||
@@ -53,14 +75,15 @@
|
|||||||
const { loading, setLoading } = useLoading();
|
const { loading, setLoading } = useLoading();
|
||||||
|
|
||||||
const taskId = ref();
|
const taskId = ref();
|
||||||
|
const task = ref<UploadTaskQueryResponse>({} as UploadTaskQueryResponse);
|
||||||
|
const selectedHost = ref();
|
||||||
const formModel = ref<UploadTaskCreateRequest>({ ...defaultForm() });
|
const formModel = ref<UploadTaskCreateRequest>({ ...defaultForm() });
|
||||||
|
const fileList = ref<Array<FileItem>>([]);
|
||||||
const status = ref<UploadTaskStatusType>(UploadTaskStatus.WAITING);
|
const status = ref<UploadTaskStatusType>(UploadTaskStatus.WAITING);
|
||||||
const filesRef = ref();
|
const filesRef = ref();
|
||||||
const hostModal = ref<any>();
|
const hostModal = ref<any>();
|
||||||
|
|
||||||
// TODO pullstatus 按钮显示就可以去掉了吧
|
// TODO pullstatus
|
||||||
// host tab
|
|
||||||
// status tab
|
|
||||||
|
|
||||||
// 设置选中主机
|
// 设置选中主机
|
||||||
const setSelectedHost = (hosts: Array<number>) => {
|
const setSelectedHost = (hosts: Array<number>) => {
|
||||||
@@ -70,7 +93,13 @@
|
|||||||
// 创建上传任务
|
// 创建上传任务
|
||||||
const doCreateUploadTask = async () => {
|
const doCreateUploadTask = async () => {
|
||||||
// 获取文件
|
// 获取文件
|
||||||
const files = filesRef.value?.getFiles();
|
const files = fileList.value.map(s => {
|
||||||
|
return {
|
||||||
|
fileId: s.uid,
|
||||||
|
filePath: s.file?.webkitRelativePath || s.file?.name,
|
||||||
|
fileSize: s.file?.size,
|
||||||
|
};
|
||||||
|
});
|
||||||
if (!files || !files.length) {
|
if (!files || !files.length) {
|
||||||
Message.error('请先选择需要上传的文件');
|
Message.error('请先选择需要上传的文件');
|
||||||
return;
|
return;
|
||||||
@@ -95,34 +124,45 @@
|
|||||||
// 取消上传任务
|
// 取消上传任务
|
||||||
const doCancelUploadTask = async () => {
|
const doCancelUploadTask = async () => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
filesRef.value?.close();
|
|
||||||
try {
|
try {
|
||||||
// 取消上传
|
// 取消上传
|
||||||
await cancelUploadTask(taskId.value, false);
|
await cancelUploadTask(taskId.value, false);
|
||||||
status.value = UploadTaskStatus.CANCELED;
|
status.value = UploadTaskStatus.WAITING;
|
||||||
|
Message.success('已取消');
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 中断上传请求
|
||||||
|
const abortUploadRequest = () => {
|
||||||
|
status.value = UploadTaskStatus.WAITING;
|
||||||
|
filesRef.value?.close();
|
||||||
|
};
|
||||||
|
|
||||||
// 上传请求结束
|
// 上传请求结束
|
||||||
const uploadRequestEnd = async () => {
|
const uploadRequestEnd = async () => {
|
||||||
if (status.value.value !== UploadTaskStatus.REQUESTING.value) {
|
if (status.value.value === UploadTaskStatus.REQUESTING.value) {
|
||||||
// 手动停止或者其他原因
|
// 如果结束后还是请求中则代表请求完毕
|
||||||
return;
|
setLoading(true);
|
||||||
}
|
try {
|
||||||
// 如果结束后还是请求中则代表请求完毕
|
// 开始上传
|
||||||
setLoading(true);
|
await startUploadTask(taskId.value);
|
||||||
try {
|
// 查询任务
|
||||||
// 开始上传
|
const { data } = await getUploadTask(taskId.value);
|
||||||
await startUploadTask(taskId.value);
|
task.value = data;
|
||||||
status.value = UploadTaskStatus.UPLOADING;
|
selectedHost.value = data.hosts[0].id;
|
||||||
} catch (e) {
|
status.value = UploadTaskStatus.UPLOADING;
|
||||||
// 设置失败
|
} catch (e) {
|
||||||
await uploadRequestError();
|
// 设置失败
|
||||||
} finally {
|
await uploadRequestError();
|
||||||
setLoading(false);
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 手动停止或者其他原因则修改为取消上传
|
||||||
|
await doCancelUploadTask();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -144,11 +184,22 @@
|
|||||||
hostModal.value.open(formModel.value.hostIdList);
|
hostModal.value.open(formModel.value.hostIdList);
|
||||||
};
|
};
|
||||||
|
|
||||||
// 清空
|
// 返回表单页面
|
||||||
const clear = () => {
|
const backFormPanel = () => {
|
||||||
status.value = UploadTaskStatus.WAITING;
|
status.value = UploadTaskStatus.WAITING;
|
||||||
|
taskId.value = undefined;
|
||||||
|
task.value = undefined as any;
|
||||||
|
selectedHost.value = undefined as any;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 清空表单
|
||||||
|
const clearForm = () => {
|
||||||
formModel.value = { ...defaultForm() };
|
formModel.value = { ...defaultForm() };
|
||||||
filesRef.value?.close();
|
};
|
||||||
|
|
||||||
|
// 清空文件
|
||||||
|
const clearFile = () => {
|
||||||
|
fileList.value = [];
|
||||||
};
|
};
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
@@ -156,7 +207,7 @@
|
|||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
@step-width: 258px;
|
@step-width: 258px;
|
||||||
@center-width: 398px;
|
@center-width: 398px;
|
||||||
@files-width: calc(100% - @step-width - 16px - @center-width - 16px);
|
@last-width: calc(100% - @step-width - 16px - @center-width - 16px);
|
||||||
|
|
||||||
.panel-container {
|
.panel-container {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
@@ -168,20 +219,21 @@
|
|||||||
padding: 16px;
|
padding: 16px;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
margin-right: 16px;
|
margin-right: 16px;
|
||||||
|
position: relative;
|
||||||
background: var(--color-bg-2);
|
background: var(--color-bg-2);
|
||||||
}
|
}
|
||||||
|
|
||||||
.step-panel-container {
|
.first-panel-container {
|
||||||
width: @step-width;
|
width: @step-width;
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-panel-container {
|
.center-panel-container {
|
||||||
width: @center-width;
|
width: @center-width;
|
||||||
}
|
}
|
||||||
|
|
||||||
.files-panel-container {
|
.last-panel-container {
|
||||||
margin-right: 0;
|
margin-right: 0;
|
||||||
width: @files-width;
|
width: @last-width;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="layout-container upload-container">
|
<div class="layout-container upload-container">
|
||||||
<!-- 上传面板 -->
|
<!-- 上传面板 -->
|
||||||
<batch-upload-panel />
|
<upload-panel />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -15,7 +15,7 @@
|
|||||||
import { onMounted } from 'vue';
|
import { onMounted } from 'vue';
|
||||||
import { useDictStore } from '@/store';
|
import { useDictStore } from '@/store';
|
||||||
import { dictKeys } from './types/const';
|
import { dictKeys } from './types/const';
|
||||||
import BatchUploadPanel from './components/batch-upload-panel.vue';
|
import UploadPanel from './components/upload-panel.vue';
|
||||||
|
|
||||||
// 加载字典值
|
// 加载字典值
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
// 上传任务状态定义
|
// 上传任务状态定义
|
||||||
export interface UploadTaskStatusType {
|
export interface UploadTaskStatusType {
|
||||||
value: string,
|
value: string;
|
||||||
step: number,
|
step: number;
|
||||||
status: string,
|
status: string;
|
||||||
|
formPanel: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 上传任务状态
|
// 上传任务状态
|
||||||
@@ -12,37 +13,50 @@ export const UploadTaskStatus = {
|
|||||||
value: 'WAITING',
|
value: 'WAITING',
|
||||||
step: 1,
|
step: 1,
|
||||||
status: 'process',
|
status: 'process',
|
||||||
|
formPanel: true,
|
||||||
},
|
},
|
||||||
// 请求中
|
// 请求中
|
||||||
REQUESTING: {
|
REQUESTING: {
|
||||||
value: 'REQUESTING',
|
value: 'REQUESTING',
|
||||||
step: 2,
|
step: 2,
|
||||||
status: 'process',
|
status: 'process',
|
||||||
|
formPanel: true,
|
||||||
},
|
},
|
||||||
// 上传中
|
// 上传中
|
||||||
UPLOADING: {
|
UPLOADING: {
|
||||||
value: 'UPLOADING',
|
value: 'UPLOADING',
|
||||||
step: 3,
|
step: 3,
|
||||||
status: 'process',
|
status: 'process',
|
||||||
|
formPanel: false,
|
||||||
},
|
},
|
||||||
// 已完成
|
// 已完成
|
||||||
FINISHED: {
|
FINISHED: {
|
||||||
value: 'FINISHED',
|
value: 'FINISHED',
|
||||||
step: 4,
|
step: 4,
|
||||||
status: 'finish',
|
status: 'finish',
|
||||||
|
formPanel: false,
|
||||||
},
|
},
|
||||||
// 已失败
|
// 已失败
|
||||||
FAILED: {
|
FAILED: {
|
||||||
value: 'FAILED',
|
value: 'FAILED',
|
||||||
step: 4,
|
step: 4,
|
||||||
status: 'error',
|
status: 'error',
|
||||||
|
formPanel: false,
|
||||||
},
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// 上传任务文件状态
|
||||||
|
export const UploadTaskFileStatus = {
|
||||||
|
// 等待中
|
||||||
|
WAITING: 'WAITING',
|
||||||
|
// 上传中
|
||||||
|
UPLOADING: 'UPLOADING',
|
||||||
|
// 已完成
|
||||||
|
FINISHED: 'FINISHED',
|
||||||
|
// 已完成
|
||||||
|
FAILED: 'FAILED',
|
||||||
// 已取消
|
// 已取消
|
||||||
CANCELED: {
|
CANCELED: 'CANCELED',
|
||||||
value: 'CANCELED',
|
|
||||||
step: 4,
|
|
||||||
status: 'error',
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// 上传任务状态 字典项
|
// 上传任务状态 字典项
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<div class="panel-header">
|
<div class="panel-header">
|
||||||
<h3>执行参数</h3>
|
<h3>执行参数</h3>
|
||||||
<!-- 操作 -->
|
<!-- 操作 -->
|
||||||
<a-button-group size="small">
|
<a-button-group size="mini">
|
||||||
<a-button @click="emits('reset')">重置</a-button>
|
<a-button @click="emits('reset')">重置</a-button>
|
||||||
<a-button type="primary" @click="emits('exec')">执行</a-button>
|
<a-button type="primary" @click="emits('exec')">执行</a-button>
|
||||||
</a-button-group>
|
</a-button-group>
|
||||||
|
|||||||
Reference in New Issue
Block a user