批量上传优化.

This commit is contained in:
lijiahangmax
2024-05-11 00:16:42 +08:00
parent 0a43e5db45
commit 978d94dddf
21 changed files with 274 additions and 111 deletions

View File

@@ -11,6 +11,7 @@ import com.orion.ops.module.asset.entity.request.upload.UploadTaskCreateRequest;
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.vo.UploadTaskCreateVO;
import com.orion.ops.module.asset.entity.vo.UploadTaskStatusVO;
import com.orion.ops.module.asset.entity.vo.UploadTaskVO;
import com.orion.ops.module.asset.service.UploadTaskService;
import io.swagger.v3.oas.annotations.Operation;
@@ -40,8 +41,6 @@ import java.util.List;
@SuppressWarnings({"ELValidationInJSP", "SpringElInspection"})
public class UploadTaskController {
// TODO 前端日志 测试删除慢吗
@Resource
private UploadTaskService uploadTaskService;
@@ -92,7 +91,7 @@ public class UploadTaskController {
@Operation(summary = "查询上传状态")
@Parameter(name = "id", description = "id", required = true)
@PreAuthorize("@ss.hasPermission('asset:upload-task:query')")
public List<UploadTaskVO> getUploadTaskStatus(@RequestParam("idList") List<Long> idList, @RequestParam("queryFiles") Boolean queryFiles) {
public List<UploadTaskStatusVO> getUploadTaskStatus(@RequestParam("idList") List<Long> idList, @RequestParam("queryFiles") Boolean queryFiles) {
return uploadTaskService.getUploadTaskStatus(idList, queryFiles);
}

View File

@@ -3,6 +3,7 @@ package com.orion.ops.module.asset.convert;
import com.orion.ops.module.asset.entity.domain.UploadTaskDO;
import com.orion.ops.module.asset.entity.request.upload.UploadTaskCreateRequest;
import com.orion.ops.module.asset.entity.request.upload.UploadTaskQueryRequest;
import com.orion.ops.module.asset.entity.vo.UploadTaskStatusVO;
import com.orion.ops.module.asset.entity.vo.UploadTaskVO;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
@@ -27,6 +28,8 @@ public interface UploadTaskConvert {
UploadTaskVO to(UploadTaskDO domain);
List<UploadTaskVO> to(List<UploadTaskDO> list);
List<UploadTaskVO> toList(List<UploadTaskDO> list);
UploadTaskStatusVO toStatus(UploadTaskDO domain);
}

View File

@@ -56,6 +56,14 @@ public class UploadTaskDO extends BaseDO {
@TableField("extra_info")
private String extraInfo;
@Schema(description = "文件数量")
@TableField("file_count")
private Integer fileCount;
@Schema(description = "主机数量")
@TableField("host_count")
private Integer hostCount;
@Schema(description = "开始时间")
@TableField("start_time")
private Date startTime;

View File

@@ -38,6 +38,9 @@ public class HostTerminalConnectDTO {
@Schema(description = "主机地址")
private String hostAddress;
@Schema(description = "系统类型")
private String osType;
@Schema(description = "端口")
private Integer port;

View File

@@ -0,0 +1,44 @@
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.Date;
import java.util.List;
/**
* 上传任务状态 视图响应对象
*
* @author Jiahang Li
* @version 1.0.7
* @since 2024-5-7 22:15
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Schema(name = "UploadTaskStatusVO", description = "上传任务状态 视图响应对象")
public class UploadTaskStatusVO implements Serializable {
private static final long serialVersionUID = 1L;
@Schema(description = "id")
private Long id;
@Schema(description = "状态")
private String status;
@Schema(description = "开始时间")
private Date startTime;
@Schema(description = "结束时间")
private Date endTime;
@Schema(description = "上传文件")
private List<UploadTaskFileVO> files;
}

View File

@@ -47,6 +47,12 @@ public class UploadTaskVO implements Serializable {
@Schema(description = "额外信息")
private String extraInfo;
@Schema(description = "文件数量")
private Integer fileCount;
@Schema(description = "主机数量")
private Integer hostCount;
@Schema(description = "开始时间")
private Date startTime;

View File

@@ -1,6 +1,7 @@
package com.orion.ops.module.asset.handler.host.upload.task;
import com.orion.lang.utils.Threads;
import com.orion.lang.utils.io.Files1;
import com.orion.lang.utils.io.Streams;
import com.orion.ops.framework.common.constant.Const;
import com.orion.ops.module.asset.dao.UploadTaskDAO;
@@ -136,7 +137,7 @@ public class FileUploadTask implements IFileUploadTask {
.map(s -> FileUploadFileItemDTO.builder()
.id(s.getId())
.fileId(s.getFileId())
.remotePath(record.getRemotePath() + Const.SLASH + s.getFilePath())
.remotePath(Files1.getPath(Const.SLASH + record.getRemotePath() + Const.SLASH + s.getFilePath()))
.status(UploadTaskFileStatusEnum.WAITING.name())
.current(0L)
.build())

View File

@@ -1,15 +1,19 @@
package com.orion.ops.module.asset.handler.host.upload.uploader;
import com.orion.lang.utils.Strings;
import com.orion.lang.utils.collect.Maps;
import com.orion.lang.utils.io.Files1;
import com.orion.lang.utils.io.Streams;
import com.orion.net.host.SessionStore;
import com.orion.net.host.sftp.SftpExecutor;
import com.orion.ops.framework.common.constant.Const;
import com.orion.ops.framework.common.file.FileClient;
import com.orion.ops.framework.common.utils.PathUtils;
import com.orion.ops.module.asset.dao.UploadTaskFileDAO;
import com.orion.ops.module.asset.define.config.AppSftpConfig;
import com.orion.ops.module.asset.entity.domain.UploadTaskFileDO;
import com.orion.ops.module.asset.entity.dto.HostTerminalConnectDTO;
import com.orion.ops.module.asset.enums.HostSshOsTypeEnum;
import com.orion.ops.module.asset.enums.UploadTaskFileStatusEnum;
import com.orion.ops.module.asset.handler.host.upload.dto.FileUploadFileItemDTO;
import com.orion.ops.module.asset.service.HostTerminalService;
@@ -23,6 +27,7 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
@@ -100,9 +105,10 @@ public class FileUploader implements IFileUploader {
private boolean initSession() {
log.info("HostFileUploader.initSession start taskId: {}, hostId: {}", taskId, hostId);
try {
// TODO 测试看看有没有问题, 则修改为 打开 executor 后 是否会connect, 不需要的话就关闭 executor 然后重新打开
// 打开会话
// 替换用户路径
HostTerminalConnectDTO connectInfo = hostTerminalService.getTerminalConnectInfo(hostId);
this.replaceRemotePathVariable(connectInfo.getOsType(), connectInfo.getUsername());
// 打开会话
this.sessionStore = hostTerminalService.openSessionStore(connectInfo);
this.executor = sessionStore.getSftpExecutor(connectInfo.getFileNameCharset());
executor.connect();
@@ -215,6 +221,27 @@ public class FileUploader implements IFileUploader {
uploadTaskFileDAO.updateById(update);
}
/**
* 替换文件路径变量
*
* @param osType osType
* @param username username
*/
private void replaceRemotePathVariable(String osType, String username) {
// 包含变量
if (!files.get(0).getRemotePath().contains(Const.DOLLAR)) {
return;
}
String home = PathUtils.getHomePath(HostSshOsTypeEnum.WINDOWS.name().equals(osType), username);
// 替换变量
Map<String, String> env = Maps.newMap(4);
env.put("username", username);
env.put("home", home);
for (FileUploadFileItemDTO file : files) {
file.setRemotePath(Files1.getPath(Strings.format(file.getRemotePath(), env)));
}
}
@Override
public void cancel() {
log.info("HostFileUploader.cancel taskId: {}, hostId: {}, canceled: {}, closed: {}", taskId, hostId, canceled, closed);

View File

@@ -5,6 +5,7 @@ import com.orion.ops.module.asset.entity.request.upload.UploadTaskCreateRequest;
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.vo.UploadTaskCreateVO;
import com.orion.ops.module.asset.entity.vo.UploadTaskStatusVO;
import com.orion.ops.module.asset.entity.vo.UploadTaskVO;
import java.util.List;
@@ -51,7 +52,7 @@ public interface UploadTaskService {
* @param queryFiles queryFiles
* @return rows
*/
List<UploadTaskVO> getUploadTaskStatus(List<Long> idList, Boolean queryFiles);
List<UploadTaskStatusVO> getUploadTaskStatus(List<Long> idList, Boolean queryFiles);
/**
* 获取上传任务数量

View File

@@ -241,6 +241,7 @@ public class HostTerminalServiceImpl implements HostTerminalService {
conn.setHostId(host.getId());
conn.setHostName(host.getName());
conn.setHostAddress(host.getAddress());
conn.setOsType(config.getOsType());
conn.setPort(config.getPort());
conn.setTimeout(config.getConnectTimeout());
conn.setCharset(config.getCharset());

View File

@@ -112,6 +112,8 @@ public class UploadTaskServiceImpl implements UploadTaskService {
record.setUsername(user.getUsername());
record.setDescription(Strings.def(record.getDescription(), () -> Strings.format(DEFAULT_DESC, Dates.current())));
record.setStatus(UploadTaskStatusEnum.WAITING.name());
record.setFileCount(files.size());
record.setHostCount(hostIdList.size());
UploadTaskExtraDTO extra = UploadTaskExtraDTO.builder()
.hostIdList(hostIdList)
.hosts(hosts)
@@ -159,7 +161,7 @@ public class UploadTaskServiceImpl implements UploadTaskService {
// 计算传输进度
this.computeUploadProgress(id, files);
// 设置任务文件
this.setTaskFiles(uploadTask, files);
this.setTaskHostFiles(uploadTask, files);
return uploadTask;
}
@@ -174,40 +176,39 @@ public class UploadTaskServiceImpl implements UploadTaskService {
}
@Override
public List<UploadTaskVO> getUploadTaskStatus(List<Long> idList, Boolean queryFiles) {
public List<UploadTaskStatusVO> getUploadTaskStatus(List<Long> idList, Boolean queryFiles) {
// 查询任务
List<UploadTaskVO> tasks = uploadTaskDAO.of()
List<UploadTaskStatusVO> tasks = uploadTaskDAO.of()
.createWrapper()
.select(UploadTaskDO::getId, UploadTaskDO::getStatus,
UploadTaskDO::getStartTime, UploadTaskDO::getEndTime)
.in(UploadTaskDO::getId, idList)
.then()
.list(UploadTaskConvert.MAPPER::to);
.list(UploadTaskConvert.MAPPER::toStatus);
if (!Booleans.isTrue(queryFiles)) {
return tasks;
}
// 查询任务文件
Map<Long, List<UploadTaskFileVO>> filesMap = uploadTaskFileDAO.of()
Map<Long, List<UploadTaskFileVO>> taskFilesMap = uploadTaskFileDAO.of()
.createWrapper()
.select(UploadTaskFileDO::getId, UploadTaskFileDO::getTaskId,
UploadTaskFileDO::getHostId, UploadTaskFileDO::getStatus,
.select(UploadTaskFileDO::getId, UploadTaskFileDO::getTaskId, UploadTaskFileDO::getHostId,
UploadTaskFileDO::getStatus, UploadTaskFileDO::getFileSize,
UploadTaskFileDO::getStartTime, UploadTaskFileDO::getEndTime)
.in(UploadTaskFileDO::getTaskId, idList)
.then()
.stream()
.map(UploadTaskFileConvert.MAPPER::to)
.collect(Collectors.groupingBy(UploadTaskFileVO::getTaskId));
for (UploadTaskVO task : tasks) {
for (UploadTaskStatusVO task : tasks) {
Long id = task.getId();
List<UploadTaskFileVO> files = filesMap.get(id);
List<UploadTaskFileVO> files = taskFilesMap.get(id);
if (files == null) {
files = Lists.empty();
} else {
// 计算进度
this.computeUploadProgress(id, files);
// 设置任务文件
}
this.setTaskFiles(task, files);
task.setFiles(files);
}
return tasks;
}
@@ -311,8 +312,8 @@ public class UploadTaskServiceImpl implements UploadTaskService {
return uploadTaskDAO.wrapper()
.eq(UploadTaskDO::getId, request.getId())
.eq(UploadTaskDO::getUserId, request.getUserId())
.in(UploadTaskDO::getDescription, request.getDescription())
.eq(UploadTaskDO::getRemotePath, request.getRemotePath())
.like(UploadTaskDO::getDescription, request.getDescription())
.like(UploadTaskDO::getRemotePath, request.getRemotePath())
.eq(UploadTaskDO::getStatus, request.getStatus())
.ge(UploadTaskDO::getCreateTime, Arrays1.getIfPresent(request.getCreateTimeRange(), 0))
.le(UploadTaskDO::getCreateTime, Arrays1.getIfPresent(request.getCreateTimeRange(), 1))
@@ -450,12 +451,12 @@ public class UploadTaskServiceImpl implements UploadTaskService {
}
/**
* 设置任务文件
* 设置主机任务文件
*
* @param task task
* @param files files
*/
private void setTaskFiles(UploadTaskVO task, List<UploadTaskFileVO> files) {
private void setTaskHostFiles(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)

View File

@@ -11,6 +11,8 @@
<result column="description" property="description"/>
<result column="status" property="status"/>
<result column="extra_info" property="extraInfo"/>
<result column="file_count" property="fileCount"/>
<result column="host_count" property="hostCount"/>
<result column="start_time" property="startTime"/>
<result column="end_time" property="endTime"/>
<result column="create_time" property="createTime"/>
@@ -22,7 +24,7 @@
<!-- 通用查询结果列 -->
<sql id="Base_Column_List">
id, user_id, username, remote_path, description, status, extra_info, start_time, end_time, create_time, update_time, creator, updater, deleted
id, user_id, username, remote_path, description, status, extra_info, file_count, host_count, start_time, end_time, create_time, update_time, creator, updater, deleted
</sql>
</mapper>

View File

@@ -53,6 +53,8 @@ export interface UploadTaskQueryResponse extends TableData {
description: string;
status: string;
extraInfo: string;
fileCount: number;
hostCount: number;
startTime: number;
endTime: number;
createTime: number;
@@ -86,6 +88,17 @@ export interface UploadTaskFile {
current: number;
}
/**
* 上传任务状态响应
*/
export interface UploadTaskStatusResponse extends TableData {
id: number;
status: string;
startTime: number;
endTime: number;
files: Array<UploadTaskFile>;
}
/**
* 创建上传任务
*/
@@ -125,7 +138,7 @@ export function getUploadTaskPage(request: UploadTaskQueryRequest) {
* 查询上传任务状态
*/
export function getUploadTaskStatus(idList: Array<number>, queryFiles: boolean) {
return axios.get<Array<UploadTaskQueryResponse>>('/asset/upload-task/status', {
return axios.get<Array<UploadTaskStatusResponse>>('/asset/upload-task/status', {
params: { idList, queryFiles },
paramsSerializer: params => {
return qs.stringify(params, { arrayFormat: 'comma' });

View File

@@ -41,14 +41,10 @@
<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">
<span class="file-name text-ellipsis"
:title="fileItem.file.webkitRelativePath || fileItem.file.name">
{{ fileItem.file.webkitRelativePath || fileItem.file.name }}
</span>
</a-tooltip>
<!-- 文件大小 -->
<span class="file-size span-blue">
{{ getFileSize(fileItem.file.size) }}
@@ -144,7 +140,7 @@
:deep(.waiting-files-wrapper) {
.arco-upload-list {
padding: 0 6px 0 0 !important;
padding: 0 12px 0 0 !important;
}
.arco-upload-list-item-name {
@@ -205,16 +201,18 @@
justify-content: space-between;
.file-name {
color: var(--color-text-1);
display: inline-block;
width: calc(100% - @file-size-width);
padding: 2px 0;
color: var(--color-text-1);
}
.file-size {
font-size: 13px;
display: inline-block;
width: @file-size-width;
text-align: end;
display: inline-flex;
font-size: 13px;
justify-content: flex-end;
align-items: center;
user-select: none;
}
}

View File

@@ -6,19 +6,19 @@
<!-- 操作 -->
<a-button-group size="mini">
<!-- 重置 -->
<a-button v-if="status.value === UploadTaskStatus.WAITING.value"
<a-button v-if="status.value === UploadTaskStepStatus.WAITING.value"
@click="emits('clear')">
重置
</a-button>
<!-- 取消上传 -->
<a-button v-if="status.value === UploadTaskStatus.REQUESTING.value"
<a-button v-if="status.value === UploadTaskStepStatus.REQUESTING.value"
type="primary"
status="warning"
@click="emits('abort')">
取消上传
</a-button>
<!-- 开始上传 -->
<a-button v-if="status.value === UploadTaskStatus.WAITING.value"
<a-button v-if="status.value === UploadTaskStepStatus.WAITING.value"
type="primary"
@click="submit">
开始上传
@@ -39,7 +39,10 @@
allow-clear />
</a-form-item>
<!-- 上传路径 -->
<a-form-item field="remotePath" label="上传路径">
<a-form-item field="remotePath"
style="margin-bottom: 4px;"
label="上传路径"
help="${username} 用户名 ${home} 家目录">
<a-input v-model="formModel.remotePath"
placeholder="请输入上传路径"
allow-clear />
@@ -71,7 +74,7 @@
import type { UploadTaskStatusType } from '../types/const';
import { ref } from 'vue';
import formRules from '../types/form.rules';
import { UploadTaskStatus } from '../types/const';
import { UploadTaskStepStatus } from '../types/const';
const emits = defineEmits(['upload', 'openHost', 'abort', 'clear']);
const props = defineProps<{

View File

@@ -8,7 +8,8 @@
<!-- 返回 -->
<a-button @click="emits('back')">返回</a-button>
<!-- 取消上传 -->
<a-button type="primary"
<a-button v-if="status.value === UploadTaskStepStatus.UPLOADING.value"
type="primary"
status="warning"
@click="emits('cancel')">
取消上传
@@ -37,14 +38,20 @@
<!-- 主机状态 -->
<a-space class="host-item-status" direction="vertical">
<!-- 未完成 -->
<a-tag class="host-item-status-tag" color="#52C41A">
<a-tag class="host-item-status-tag"
color="#73D13D"
title="未完成数量"
size="small">
{{ 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">
<a-tag class="host-item-status-tag"
color="#40A9FF"
title="已完成数量"
size="small">
{{ getFinishCount(host.files) }}
<template #icon>
<icon-check-circle class="host-item-status-icon" />
@@ -66,10 +73,13 @@
<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';
import type { UploadTaskStatusType } from '../types/const';
import { UploadTaskStepStatus } from '../types/const';
import { UploadTaskFileStatus } from '@/views/exec/upload-task/types/const';
const emits = defineEmits(['update:selectedHost', 'back', 'cancel']);
const props = defineProps<{
status: UploadTaskStatusType;
selectedHost: number;
task: UploadTaskQueryResponse;
}>();
@@ -126,6 +136,7 @@
&-tag {
max-width: 64px;
width: 100%;
}
&-icon {

View File

@@ -16,12 +16,28 @@
<div class="file-item-path text-ellipsis" :title="file.filePath">
{{ file.filePath }}
</div>
<!-- 状态 -->
<div class="file-item-status">
<!-- 文件大小 -->
<div class="file-item-size span-blue">
<!-- 当前大小 -->
<template v-if="file.status === UploadTaskFileStatus.WAITING || file.status === UploadTaskFileStatus.UPLOADING">
{{ getFileSize(file.current || 0) }}
</template>
<!-- 总大小 -->
<template v-else>
{{ getFileSize(file.fileSize) }}
</template>
</div>
<!-- 进度 -->
<div class="file-item-progress">
<a-tooltip position="left"
:content="((file.current || 0) / file.fileSize * 100).toFixed(2) + '%'"
mini>
<a-progress type="circle"
size="mini"
:status="getDictValue(fileStatusKey, file.status, 'status') as any"
:percent="file.current / file.fileSize" />
:percent="(file.current || 0) / file.fileSize" />
</a-tooltip>
</div>
</div>
</a-scrollbar>
@@ -38,7 +54,9 @@
<script lang="ts" setup>
import type { UploadTaskFile } from '@/api/exec/upload-task';
import { fileStatusKey } from '../types/const';
import { UploadTaskFileStatus } from '@/views/exec/upload-task/types/const';
import { useDictStore } from '@/store';
import { getFileSize } from '@/utils/file';
const emits = defineEmits(['update:selectedHost']);
const props = defineProps<{
@@ -47,12 +65,11 @@
const { getDictValue } = useDictStore();
</script>
<style lang="less" scoped>
@icon-width: 24px;
@progress-width: 24px;
@status-width: 102px;
.wrapper {
width: 100%;
@@ -83,15 +100,24 @@
}
&-path {
width: calc(100% - @icon-width - @progress-width);
padding: 2px 0;
width: calc(100% - @icon-width - @status-width);
display: inline-block;
font-size: 14px;
color: var(--color-text-1);
}
&-progress {
width: @progress-width;
&-size {
font-size: 12px;
margin-right: 12px;
user-select: none;
}
&-status {
width: @status-width;
display: flex;
justify-content: flex-end;
align-items: center;
}
}
}

View File

@@ -2,12 +2,12 @@
<a-spin class="panel-container full" :loading="loading">
<!-- 上传步骤 -->
<batch-upload-step class="panel-item first-panel-container"
:status="status" />
:status="taskStatus" />
<!-- 上传表单 -->
<batch-upload-form v-if="status.formPanel"
<batch-upload-form v-if="taskStatus.formPanel"
class="panel-item center-panel-container"
:form-model="formModel"
:status="status"
:status="taskStatus"
@upload="doCreateUploadTask"
@abort="abortUploadRequest"
@open-host="openHostModal"
@@ -16,11 +16,12 @@
<batch-upload-hosts v-else
class="panel-item center-panel-container"
v-model:selected-host="selectedHost"
:status="taskStatus"
:task="task"
@back="backFormPanel"
@cancel="doCancelUploadTask" />
<!-- 文件列表 -->
<batch-upload-files v-if="status.formPanel"
<batch-upload-files v-if="taskStatus.formPanel"
v-model:file-list="fileList"
class="panel-item last-panel-container"
ref="filesRef"
@@ -51,9 +52,10 @@
import type { FileItem } from '@arco-design/web-vue';
import type { UploadTaskCreateRequest, UploadTaskQueryResponse } from '@/api/exec/upload-task';
import type { UploadTaskStatusType } from '../types/const';
import { ref } from 'vue';
import { UploadTaskStatus } from '../types/const';
import { cancelUploadTask, createUploadTask, startUploadTask, getUploadTask } from '@/api/exec/upload-task';
import { onMounted, onUnmounted, ref } from 'vue';
import { UploadTaskStepStatus } from '../types/const';
import { UploadTaskStatus } from '@/views/exec/upload-task/types/const';
import { cancelUploadTask, createUploadTask, startUploadTask, getUploadTask, getUploadTaskStatus } from '@/api/exec/upload-task';
import useLoading from '@/hooks/loading';
import { Message } from '@arco-design/web-vue';
import BatchUploadStep from './batch-upload-step.vue';
@@ -66,24 +68,23 @@
const defaultForm = (): UploadTaskCreateRequest => {
return {
description: '',
remotePath: '/root/batch',
hostIdList: [1],
remotePath: '',
hostIdList: [],
files: []
};
};
const { loading, setLoading } = useLoading();
const pullStatusId = ref();
const taskId = ref();
const task = ref<UploadTaskQueryResponse>({} as UploadTaskQueryResponse);
const selectedHost = ref();
const formModel = ref<UploadTaskCreateRequest>({ ...defaultForm() });
const fileList = ref<Array<FileItem>>([]);
const status = ref<UploadTaskStatusType>(UploadTaskStatus.WAITING);
const taskStatus = ref<UploadTaskStatusType>(UploadTaskStepStatus.WAITING);
const filesRef = ref();
const hostModal = ref<any>();
// TODO pullstatus
const hostModal = ref();
// 设置选中主机
const setSelectedHost = (hosts: Array<number>) => {
@@ -106,16 +107,16 @@
}
// 创建任务
setLoading(true);
status.value = UploadTaskStatus.WAITING;
taskStatus.value = UploadTaskStepStatus.WAITING;
try {
formModel.value.files = files;
const { data } = await createUploadTask(formModel.value);
taskId.value = data.id;
status.value = UploadTaskStatus.REQUESTING;
taskStatus.value = UploadTaskStepStatus.REQUESTING;
// 上传文件
await filesRef.value.startUpload(data.token);
} catch (e) {
status.value = UploadTaskStatus.FAILED;
taskStatus.value = UploadTaskStepStatus.FAILED;
} finally {
setLoading(false);
}
@@ -127,7 +128,7 @@
try {
// 取消上传
await cancelUploadTask(taskId.value, false);
status.value = UploadTaskStatus.WAITING;
taskStatus.value = UploadTaskStepStatus.WAITING;
Message.success('已取消');
} catch (e) {
} finally {
@@ -137,13 +138,13 @@
// 中断上传请求
const abortUploadRequest = () => {
status.value = UploadTaskStatus.WAITING;
taskStatus.value = UploadTaskStepStatus.WAITING;
filesRef.value?.close();
};
// 上传请求结束
const uploadRequestEnd = async () => {
if (status.value.value === UploadTaskStatus.REQUESTING.value) {
if (taskStatus.value.value === UploadTaskStepStatus.REQUESTING.value) {
// 如果结束后还是请求中则代表请求完毕
setLoading(true);
try {
@@ -153,7 +154,7 @@
const { data } = await getUploadTask(taskId.value);
task.value = data;
selectedHost.value = data.hosts[0].id;
status.value = UploadTaskStatus.UPLOADING;
taskStatus.value = UploadTaskStepStatus.UPLOADING;
} catch (e) {
// 设置失败
await uploadRequestError();
@@ -172,13 +173,48 @@
try {
// 开始上传
await cancelUploadTask(taskId.value, true);
status.value = UploadTaskStatus.FAILED;
taskStatus.value = UploadTaskStepStatus.FAILED;
} catch (e) {
} finally {
setLoading(false);
}
};
// 加载轮询状态
const pullTaskStatus = async () => {
if (!taskId.value || !task.value) {
return;
}
// 非上传中则不查询
if (taskStatus.value.value !== UploadTaskStepStatus.UPLOADING.value) {
return;
}
// 查询状态
const { data } = await getUploadTaskStatus([taskId.value], true);
if (!data.length) {
return;
}
const taskStatusData = data[0];
// 设置任务状态
if (taskStatusData.status === UploadTaskStatus.FINISHED) {
taskStatus.value = UploadTaskStepStatus.FINISHED;
} else if (taskStatusData.status === UploadTaskStatus.CANCELED) {
taskStatus.value = UploadTaskStepStatus.FINISHED;
} else if (taskStatusData.status === UploadTaskStatus.FAILED) {
taskStatus.value = UploadTaskStepStatus.FAILED;
}
// 设置文件进度
for (let host of task.value.hosts) {
for (let file of host.files) {
const fileStatus = taskStatusData.files.find(s => s.id === file.id);
if (fileStatus) {
file.status = fileStatus.status;
file.current = fileStatus.current;
}
}
}
};
// 打开主机模态框
const openHostModal = () => {
hostModal.value.open(formModel.value.hostIdList);
@@ -186,7 +222,7 @@
// 返回表单页面
const backFormPanel = () => {
status.value = UploadTaskStatus.WAITING;
taskStatus.value = UploadTaskStepStatus.WAITING;
taskId.value = undefined;
task.value = undefined as any;
selectedHost.value = undefined as any;
@@ -202,6 +238,16 @@
fileList.value = [];
};
// 设置轮询状态
onMounted(() => {
pullStatusId.value = setInterval(pullTaskStatus, 5000);
});
// 卸载状态查询
onUnmounted(() => {
clearInterval(pullStatusId.value);
});
</script>
<style lang="less" scoped>

View File

@@ -7,7 +7,7 @@ export interface UploadTaskStatusType {
}
// 上传任务状态
export const UploadTaskStatus = {
export const UploadTaskStepStatus = {
// 等待中
WAITING: {
value: 'WAITING',
@@ -45,20 +45,6 @@ export const UploadTaskStatus = {
},
};
// 上传任务文件状态
export const UploadTaskFileStatus = {
// 等待中
WAITING: 'WAITING',
// 上传中
UPLOADING: 'UPLOADING',
// 已完成
FINISHED: 'FINISHED',
// 已完成
FAILED: 'FAILED',
// 已取消
CANCELED: 'CANCELED',
};
// 上传任务状态 字典项
export const taskStatusKey = 'uploadTaskStatus';

View File

@@ -102,6 +102,7 @@
};
defineExpose({ open });
// 确定
const handlerOk = async () => {
setLoading(true);

View File

@@ -1,17 +0,0 @@
<template>
<div>upload-task-log</div>
</template>
<script lang="ts">
export default {
name: 'index'
};
</script>
<script lang="ts" setup>
</script>
<style lang="less" scoped>
</style>