feat:2.4.0

1. 完成的控制台的日志 任务 批次列表页和详情页部分内容
This commit is contained in:
byteblogs168 2023-10-14 17:08:17 +08:00
parent 8a6d16b44b
commit b3c4cd92c1
33 changed files with 870 additions and 690 deletions

View File

@ -35,8 +35,6 @@ public enum JobTaskStatusEnum {
* 任务停止
*/
STOP(5),
;
private final int status;

View File

@ -8,7 +8,8 @@
<result column="group_name" property="groupName" />
<result column="job_id" property="jobId" />
<result column="task_id" property="taskId" />
<result column="task_instance_id" property="taskInstanceId" />
<result column="client_address" property="clientAddress"/>
<result column="task_batch_id" property="taskBatchId" />
<result column="create_dt" property="createDt" />
<result column="message" property="message" />
</resultMap>

View File

@ -18,7 +18,6 @@ import java.util.Objects;
public class RequestBuilder<T, R> {
private Class<T> clintInterface;
private String groupName;
private RegisterNodeInfo nodeInfo;
private boolean failRetry;
private int retryTimes = 3;
@ -43,10 +42,10 @@ public class RequestBuilder<T, R> {
return this;
}
public RequestBuilder<T, R> groupName(String groupName) {
this.groupName = groupName;
return this;
}
// public RequestBuilder<T, R> groupName(String groupName) {
// this.groupName = groupName;
// return this;
// }
public RequestBuilder<T, R> failRetry(boolean failRetry) {
this.failRetry = failRetry;
@ -68,7 +67,7 @@ public class RequestBuilder<T, R> {
return this;
}
public RequestBuilder<T, R> allocKey(boolean failover) {
public RequestBuilder<T, R> failover(boolean failover) {
this.failover = failover;
return this;
}
@ -89,7 +88,6 @@ public class RequestBuilder<T, R> {
throw new EasyRetryServerException("clintInterface cannot be null");
}
Assert.notBlank(groupName, () -> new EasyRetryServerException("groupName cannot be null"));
Assert.notNull(nodeInfo, () -> new EasyRetryServerException("nodeInfo cannot be null"));
if (failover) {
@ -103,7 +101,7 @@ public class RequestBuilder<T, R> {
}
RpcClientInvokeHandler clientInvokeHandler = new RpcClientInvokeHandler(
groupName, nodeInfo, failRetry, retryTimes, retryInterval, retryListener, routeKey, allocKey, failover);
nodeInfo.getGroupName(), nodeInfo, failRetry, retryTimes, retryInterval, retryListener, routeKey, allocKey, failover);
return (T) Proxy.newProxyInstance(clintInterface.getClassLoader(),
new Class[]{clintInterface}, clientInvokeHandler);

View File

@ -65,13 +65,18 @@ public interface JobTaskConverter {
DispatchJobRequest toDispatchJobRequest(RealJobExecutorDTO realJobExecutorDTO);
@Mappings({
@Mapping(source = "job.groupName", target = "groupName"),
@Mapping(source = "jobTask.groupName", target = "groupName"),
@Mapping(source = "jobTask.jobId", target = "jobId"),
@Mapping(source = "jobTask.taskBatchId", target = "taskBatchId"),
@Mapping(source = "jobTask.clientId", target = "clientId"),
@Mapping(source = "jobTask.id", target = "taskId"),
@Mapping(source = "jobTask.argsStr", target = "argsStr"),
@Mapping(source = "jobTask.argsType", target = "argsType"),
@Mapping(source = "jobTask.extAttrs", target = "extAttrs")
})
RealJobExecutorDTO toRealJobExecutorDTO(Job job, JobTask jobTask);
RealJobExecutorDTO toRealJobExecutorDTO(JobExecutorContext context, JobTask jobTask);
JobExecutorContext toJobExecutorContext(Job job);
JobExecutorResultDTO toJobExecutorResultDTO(ClientCallbackContext context);

View File

@ -5,6 +5,7 @@ import com.aizuda.easy.retry.common.core.log.LogUtils;
import com.aizuda.easy.retry.server.common.akka.ActorGenerator;
import com.aizuda.easy.retry.server.job.task.dto.TaskExecuteDTO;
import com.aizuda.easy.retry.server.job.task.support.JobExecutor;
import com.aizuda.easy.retry.server.job.task.support.JobTaskConverter;
import com.aizuda.easy.retry.server.job.task.support.executor.JobExecutorContext;
import com.aizuda.easy.retry.server.job.task.support.executor.JobExecutorFactory;
import com.aizuda.easy.retry.template.datasource.persistence.mapper.JobMapper;
@ -44,12 +45,10 @@ public class JobExecutorActor extends AbstractActor {
Job job = jobMapper.selectById(taskExecute.getJobId());
JobExecutor jobExecutor = JobExecutorFactory.getJobExecutor(job.getTaskType());
JobExecutorContext context = new JobExecutorContext();
JobExecutorContext context = JobTaskConverter.INSTANCE.toJobExecutorContext(job);
context.setTaskBatchId(taskExecute.getTaskBatchId());
context.setGroupName(taskExecute.getGroupName());
context.setJobId(job.getId());
context.setTaskType(job.getTaskType());
context.setJob(job);
jobExecutor.execute(context);
}

View File

@ -49,7 +49,7 @@ public class JobLogActor extends AbstractActor {
JobLogMessage jobLogMessage = JobTaskConverter.INSTANCE.toJobLogMessage(jobLogDTO);
if (Objects.nonNull(jobLogDTO.getClientId())) {
Optional.ofNullable(CacheRegisterTable.getServerNode(jobLogDTO.getGroupName(), jobLogDTO.getClientId())).ifPresent(registerNodeInfo -> {
jobLogMessage.setClientAddress(registerNodeInfo.fullUrl());
jobLogMessage.setClientAddress(registerNodeInfo.address());
});
}

View File

@ -29,11 +29,10 @@ public class BroadcastTaskJobExecutor extends AbstractJobExecutor {
@Override
protected void doExecute(JobExecutorContext context) {
Job job = context.getJob();
List<JobTask> taskList = context.getTaskList();
for (JobTask jobTask : taskList) {
RealJobExecutorDTO realJobExecutor = JobTaskConverter.INSTANCE.toRealJobExecutorDTO(job, jobTask);
RealJobExecutorDTO realJobExecutor = JobTaskConverter.INSTANCE.toRealJobExecutorDTO(context, jobTask);
ActorRef actorRef = ActorGenerator.jobRealTaskExecutorActor();
actorRef.tell(realJobExecutor, actorRef);
}

View File

@ -31,9 +31,8 @@ public class ClusterJobExecutor extends AbstractJobExecutor {
protected void doExecute(JobExecutorContext context) {
// 调度客户端
Job job = context.getJob();
List<JobTask> taskList = context.getTaskList();
RealJobExecutorDTO realJobExecutor = JobTaskConverter.INSTANCE.toRealJobExecutorDTO(job, taskList.get(0));
RealJobExecutorDTO realJobExecutor = JobTaskConverter.INSTANCE.toRealJobExecutorDTO(context, taskList.get(0));
ActorRef actorRef = ActorGenerator.jobRealTaskExecutorActor();
actorRef.tell(realJobExecutor, actorRef);

View File

@ -1,6 +1,5 @@
package com.aizuda.easy.retry.server.job.task.support.executor;
import com.aizuda.easy.retry.template.datasource.persistence.po.Job;
import com.aizuda.easy.retry.template.datasource.persistence.po.JobTask;
import lombok.Data;
@ -48,4 +47,37 @@ public class JobExecutorContext {
private Integer routeKey;
/**
* 扩展字段
*/
private String extAttrs;
private Long taskId;
private Integer parallelNum;
private Integer executorType;
private String executorName;
private String clientId;
/**
* 最大重试次数
*/
private Integer maxRetryTimes;
/**
* 重试间隔(s)
*/
private Integer retryInterval;
private Integer shardingTotal;
private Integer shardingIndex;
private Integer executorTimeout;
}

View File

@ -115,7 +115,6 @@ public class RealJobExecutorActor extends AbstractActor {
private JobRpcClient buildRpcClient(RegisterNodeInfo registerNodeInfo, RealJobExecutorDTO realJobExecutorDTO) {
return RequestBuilder.<JobRpcClient, Result>newBuilder()
.groupName(registerNodeInfo.getGroupName())
.nodeInfo(registerNodeInfo)
.failRetry(Boolean.TRUE)
.retryTimes(realJobExecutorDTO.getMaxRetryTimes())

View File

@ -30,10 +30,9 @@ public class ShardingJobExecutor extends AbstractJobExecutor {
@Override
protected void doExecute(JobExecutorContext context) {
Job job = context.getJob();
List<JobTask> taskList = context.getTaskList();
for (int i = 0; i < taskList.size(); i++) {
RealJobExecutorDTO realJobExecutor = JobTaskConverter.INSTANCE.toRealJobExecutorDTO(job, taskList.get(i));
RealJobExecutorDTO realJobExecutor = JobTaskConverter.INSTANCE.toRealJobExecutorDTO(context, taskList.get(i));
realJobExecutor.setShardingIndex(i);
realJobExecutor.setShardingTotal(taskList.size());
ActorRef actorRef = ActorGenerator.jobRealTaskExecutorActor();

View File

@ -49,11 +49,7 @@ public class RealStopTaskActor extends AbstractActor {
private Result<Boolean> requestClient(RealStopTaskInstanceDTO realStopTaskInstanceDTO, RegisterNodeInfo registerNodeInfo) {
JobRpcClient rpcClient = RequestBuilder.<JobRpcClient, Result>newBuilder()
.hostPort(registerNodeInfo.getHostPort())
.groupName(realStopTaskInstanceDTO.getGroupName())
.hostId(registerNodeInfo.getHostId())
.hostIp(registerNodeInfo.getHostIp())
.contextPath(registerNodeInfo.getContextPath())
.nodeInfo(registerNodeInfo)
.failRetry(Boolean.TRUE)
.retryTimes(3)
.retryInterval(1)

View File

@ -22,10 +22,10 @@ import com.aizuda.easy.retry.server.common.client.annotation.Mapping;
*/
public interface RetryRpcClient {
@Mapping(path = "/retry/dispatch/v1", method = RequestMethod.POST, failover = true)
@Mapping(path = "/retry/dispatch/v1", method = RequestMethod.POST)
Result<DispatchRetryResultDTO> dispatch(@Body DispatchRetryDTO dispatchRetryDTO, @Header EasyRetryHeaders headers);
@Mapping(path = "/retry/callback/v1", method = RequestMethod.POST, failover = true)
@Mapping(path = "/retry/callback/v1", method = RequestMethod.POST)
Result callback(@Body RetryCallbackDTO retryCallbackDTO);
@Mapping(path = "/retry/generate/idempotent-id/v1", method = RequestMethod.POST)

View File

@ -2,6 +2,7 @@ package com.aizuda.easy.retry.server.retry.task.support;
import com.aizuda.easy.retry.server.common.dto.RegisterNodeInfo;
import com.aizuda.easy.retry.template.datasource.persistence.po.RetryTask;
import com.aizuda.easy.retry.template.datasource.persistence.po.SceneConfig;
import java.util.Set;
@ -74,4 +75,10 @@ public interface RetryContext<V> {
*/
Set<String> getSceneBlacklist();
/**
* 路由策略
*
* @return 路由策略
*/
SceneConfig sceneConfig();
}

View File

@ -4,6 +4,7 @@ import com.aizuda.easy.retry.server.common.dto.RegisterNodeInfo;
import com.aizuda.easy.retry.server.retry.task.support.RetryContext;
import com.aizuda.easy.retry.server.retry.task.support.WaitStrategy;
import com.aizuda.easy.retry.template.datasource.persistence.po.RetryTask;
import com.aizuda.easy.retry.template.datasource.persistence.po.SceneConfig;
import lombok.Data;
import java.util.Objects;
@ -47,9 +48,19 @@ public class CallbackRetryContext<V> implements RetryContext<V> {
*/
private RegisterNodeInfo serverNode;
/**
* 场景配置
*/
private SceneConfig sceneConfig;
@Override
public boolean hasException() {
return Objects.nonNull(exception);
}
@Override
public SceneConfig sceneConfig() {
return sceneConfig;
}
}

View File

@ -4,6 +4,7 @@ import com.aizuda.easy.retry.server.common.dto.RegisterNodeInfo;
import com.aizuda.easy.retry.server.retry.task.support.RetryContext;
import com.aizuda.easy.retry.server.retry.task.support.WaitStrategy;
import com.aizuda.easy.retry.template.datasource.persistence.po.RetryTask;
import com.aizuda.easy.retry.template.datasource.persistence.po.SceneConfig;
import lombok.Data;
import lombok.Getter;
@ -50,6 +51,11 @@ public class MaxAttemptsPersistenceRetryContext<V> implements RetryContext<V> {
*/
private RegisterNodeInfo serverNode;
/**
* 场景配置
*/
private SceneConfig sceneConfig;
@Override
public void setCallResult(V v) {
this.callResult = v;
@ -64,4 +70,10 @@ public class MaxAttemptsPersistenceRetryContext<V> implements RetryContext<V> {
public boolean hasException() {
return Objects.nonNull(exception);
}
@Override
public SceneConfig sceneConfig() {
return sceneConfig;
}
}

View File

@ -22,6 +22,7 @@ import com.aizuda.easy.retry.server.retry.task.support.retry.RetryExecutor;
import com.aizuda.easy.retry.template.datasource.access.AccessTemplate;
import com.aizuda.easy.retry.template.datasource.access.TaskAccess;
import com.aizuda.easy.retry.template.datasource.persistence.po.RetryTask;
import com.aizuda.easy.retry.template.datasource.persistence.po.SceneConfig;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import lombok.extern.slf4j.Slf4j;
@ -44,7 +45,7 @@ import java.util.concurrent.Callable;
@Component(ActorGenerator.EXEC_CALLBACK_UNIT_ACTOR)
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Slf4j
public class ExecCallbackUnitActor extends AbstractActor {
public class ExecCallbackUnitActor extends AbstractActor {
@Autowired
@Qualifier("bitSetIdempotentStrategyHandler")
@ -61,6 +62,7 @@ public class ExecCallbackUnitActor extends AbstractActor {
CallbackRetryContext context = (CallbackRetryContext) retryExecutor.getRetryContext();
RetryTask retryTask = context.getRetryTask();
RegisterNodeInfo serverNode = context.getServerNode();
SceneConfig sceneConfig = context.getSceneConfig();
RetryTaskLogDTO retryTaskLog = new RetryTaskLogDTO();
retryTaskLog.setGroupName(retryTask.getGroupName());
@ -70,7 +72,7 @@ public class ExecCallbackUnitActor extends AbstractActor {
if (Objects.nonNull(serverNode)) {
retryExecutor.call((Callable<Result<Void>>) () -> {
Result<Void> result = callClient(retryTask, serverNode);
Result<Void> result = callClient(retryTask, serverNode, sceneConfig);
String message = "回调客户端成功";
if (StatusEnum.YES.getStatus() != result.getStatus()) {
@ -90,7 +92,7 @@ public class ExecCallbackUnitActor extends AbstractActor {
retryTaskLog.setMessage("There are currently no available client PODs.");
}
}catch (Exception e) {
} catch (Exception e) {
LogUtils.error(log, "callback client error. retryTask:[{}]", JsonUtil.toJsonString(retryTask), e);
retryTaskLog.setMessage(StringUtils.isBlank(e.getMessage()) ? StrUtil.EMPTY : e.getMessage());
} finally {
@ -114,15 +116,15 @@ public class ExecCallbackUnitActor extends AbstractActor {
* @param callbackTask {@link RetryTask} 回调任务
* @return 重试结果返回值
*/
private Result callClient(RetryTask callbackTask, RegisterNodeInfo serverNode) {
private Result callClient(RetryTask callbackTask, RegisterNodeInfo serverNode, SceneConfig sceneConfig) {
String retryTaskUniqueId = callbackRetryTaskHandler.getRetryTaskUniqueId(callbackTask.getUniqueId());
TaskAccess<RetryTask> retryTaskAccess = accessTemplate.getRetryTaskAccess();
RetryTask retryTask = retryTaskAccess.one(callbackTask.getGroupName(),
new LambdaQueryWrapper<RetryTask>().eq(RetryTask::getUniqueId, retryTaskUniqueId));
new LambdaQueryWrapper<RetryTask>().eq(RetryTask::getUniqueId, retryTaskUniqueId));
Assert.notNull(retryTask, () -> new EasyRetryServerException("未查询回调任务对应的重试任务. callbackUniqueId:[{}] uniqueId:[{}]",
callbackTask.getUniqueId(), retryTaskUniqueId));
callbackTask.getUniqueId(), retryTaskUniqueId));
// 回调参数
RetryCallbackDTO retryCallbackDTO = new RetryCallbackDTO();
@ -136,17 +138,13 @@ public class ExecCallbackUnitActor extends AbstractActor {
retryCallbackDTO.setUniqueId(callbackTask.getUniqueId());
RetryRpcClient rpcClient = RequestBuilder.<RetryRpcClient, Result>newBuilder()
.hostPort(serverNode.getHostPort())
.groupName(serverNode.getGroupName())
.hostId(serverNode.getHostId())
.hostIp(serverNode.getHostIp())
.contextPath(serverNode.getContextPath())
.client(RetryRpcClient.class)
.build();
.nodeInfo(serverNode)
.failover(Boolean.TRUE)
.routeKey(sceneConfig.getRouteKey())
.allocKey(sceneConfig.getSceneName())
.client(RetryRpcClient.class)
.build();
return rpcClient.callback(retryCallbackDTO);
}
}

View File

@ -21,6 +21,7 @@ import com.aizuda.easy.retry.server.retry.task.support.context.MaxAttemptsPersis
import com.aizuda.easy.retry.server.retry.task.support.dispatch.actor.log.RetryTaskLogDTO;
import com.aizuda.easy.retry.server.retry.task.support.retry.RetryExecutor;
import com.aizuda.easy.retry.template.datasource.persistence.po.RetryTask;
import com.aizuda.easy.retry.template.datasource.persistence.po.SceneConfig;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
@ -42,7 +43,7 @@ import java.util.concurrent.Callable;
@Component(ActorGenerator.EXEC_UNIT_ACTOR)
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Slf4j
public class ExecUnitActor extends AbstractActor {
public class ExecUnitActor extends AbstractActor {
@Autowired
@Qualifier("bitSetIdempotentStrategyHandler")
@ -55,6 +56,7 @@ public class ExecUnitActor extends AbstractActor {
MaxAttemptsPersistenceRetryContext context = (MaxAttemptsPersistenceRetryContext) retryExecutor.getRetryContext();
RetryTask retryTask = context.getRetryTask();
RegisterNodeInfo serverNode = context.getServerNode();
SceneConfig sceneConfig = context.getSceneConfig();
RetryTaskLogDTO retryTaskLog = new RetryTaskLogDTO();
retryTaskLog.setGroupName(retryTask.getGroupName());
@ -67,7 +69,7 @@ public class ExecUnitActor extends AbstractActor {
retryExecutor.call((Callable<Result<DispatchRetryResultDTO>>) () -> {
Result<DispatchRetryResultDTO> result = callClient(retryTask, serverNode);
Result<DispatchRetryResultDTO> result = callClient(retryTask, serverNode, sceneConfig);
// 回调接口请求成功处理返回值
if (StatusEnum.YES.getStatus() != result.getStatus()) {
@ -106,7 +108,7 @@ public class ExecUnitActor extends AbstractActor {
retryTaskLog.setMessage("There are currently no available client PODs.");
}
}catch (Exception e) {
} catch (Exception e) {
LogUtils.error(log, "callback client error. retryTask:[{}]", JsonUtil.toJsonString(retryTask), e);
retryTaskLog.setMessage(e.getMessage());
} finally {
@ -128,7 +130,7 @@ public class ExecUnitActor extends AbstractActor {
* @param retryTask {@link RetryTask} 需要重试的数据
* @return 重试结果返回值
*/
private Result<DispatchRetryResultDTO> callClient(RetryTask retryTask, RegisterNodeInfo serverNode) {
private Result<DispatchRetryResultDTO> callClient(RetryTask retryTask, RegisterNodeInfo serverNode, SceneConfig sceneConfig) {
DispatchRetryDTO dispatchRetryDTO = new DispatchRetryDTO();
dispatchRetryDTO.setIdempotentId(retryTask.getIdempotentId());
@ -139,20 +141,17 @@ public class ExecUnitActor extends AbstractActor {
dispatchRetryDTO.setRetryCount(retryTask.getRetryCount());
// 设置header
HttpHeaders requestHeaders = new HttpHeaders();
EasyRetryHeaders easyRetryHeaders = new EasyRetryHeaders();
easyRetryHeaders.setEasyRetry(Boolean.TRUE);
easyRetryHeaders.setEasyRetryId(retryTask.getUniqueId());
requestHeaders.add(SystemConstants.EASY_RETRY_HEAD_KEY, JsonUtil.toJsonString(easyRetryHeaders));
RetryRpcClient rpcClient = RequestBuilder.<RetryRpcClient, Result>newBuilder()
.hostPort(serverNode.getHostPort())
.groupName(serverNode.getGroupName())
.hostId(serverNode.getHostId())
.hostIp(serverNode.getHostIp())
.contextPath(serverNode.getContextPath())
.client(RetryRpcClient.class)
.build();
.nodeInfo(serverNode)
.failover(Boolean.TRUE)
.allocKey(retryTask.getSceneName())
.routeKey(sceneConfig.getRouteKey())
.client(RetryRpcClient.class)
.build();
return rpcClient.dispatch(dispatchRetryDTO, easyRetryHeaders);
}

View File

@ -35,6 +35,7 @@ public class CallbackTaskExecutor extends AbstractTaskExecutor {
retryContext.setServerNode(
clientNodeAllocateHandler.getServerNode(retryTask.getSceneName(), retryTask.getGroupName(),
sceneConfig.getRouteKey()));
retryContext.setSceneConfig(sceneConfig);
return retryContext;
}

View File

@ -38,6 +38,7 @@ public class ManualCallbackTaskExecutor extends AbstractTaskExecutor {
retryContext.setServerNode(
clientNodeAllocateHandler.getServerNode(retryTask.getSceneName(), retryTask.getGroupName(),
sceneConfig.getRouteKey()));
retryContext.setSceneConfig(sceneConfig);
return retryContext;
}

View File

@ -38,7 +38,9 @@ public class ManualRetryTaskExecutor extends AbstractTaskExecutor {
retryContext.setSceneBlacklist(accessTemplate.getSceneConfigAccess().getBlacklist(groupName));
retryContext.setServerNode(
clientNodeAllocateHandler.getServerNode(retryTask.getSceneName(), retryTask.getGroupName(),
sceneConfig.getRouteKey())); return retryContext;
sceneConfig.getRouteKey()));
retryContext.setSceneConfig(sceneConfig);
return retryContext;
}
@Override

View File

@ -36,6 +36,7 @@ public class RetryTaskExecutor extends AbstractTaskExecutor {
retryContext.setServerNode(
clientNodeAllocateHandler.getServerNode(retryTask.getSceneName(), retryTask.getGroupName(),
sceneConfig.getRouteKey()));
retryContext.setSceneConfig(sceneConfig);
return retryContext;
}
@ -43,7 +44,6 @@ public class RetryTaskExecutor extends AbstractTaskExecutor {
protected RetryExecutor<Result<DispatchRetryResultDTO>> builderResultRetryExecutor(RetryContext retryContext,
final SceneConfig sceneConfig) {
RetryTask retryTask = retryContext.getRetryTask();
return RetryBuilder.<Result<DispatchRetryResultDTO>>newBuilder()
.withStopStrategy(StopStrategies.stopException())
.withStopStrategy(StopStrategies.stopResultStatusCode())

View File

@ -226,11 +226,7 @@ public class RetryTaskServiceImpl implements RetryTaskService {
generateRetryIdempotentIdDTO.setExecutorName(generateRetryIdempotentIdVO.getExecutorName());
RetryRpcClient rpcClient = RequestBuilder.<RetryRpcClient, Result>newBuilder()
.hostPort(serverNode.getHostPort())
.groupName(serverNode.getGroupName())
.hostId(serverNode.getHostId())
.hostIp(serverNode.getHostIp())
.contextPath(serverNode.getContextPath())
.nodeInfo(serverNode)
.client(RetryRpcClient.class)
.build();

View File

@ -8,12 +8,33 @@ const jobApi = {
// 任务批次
jobBatchList: '/job/batch/list',
jobBatchDetail: '/job/batch/'
jobBatchDetail: '/job/batch/',
// 任务
jobTaskList: '/job/task/list',
// 日志
jobLogList: '/job/log/list'
}
export default jobApi
export function jobLogList (parameter) {
return request({
url: jobApi.jobLogList,
method: 'get',
params: parameter
})
}
export function jobTaskList (parameter) {
return request({
url: jobApi.jobTaskList,
method: 'get',
params: parameter
})
}
export function jobBatchList (parameter) {
return request({
url: jobApi.jobBatchList,

View File

@ -143,15 +143,30 @@ export const asyncRouterMap = [
},
{
path: '/job/batch/list',
name: 'JobBatch',
component: () => import('@/views/job/JobBatch'),
name: 'JobBatchList',
component: () => import('@/views/job/JobBatchList'),
meta: { title: '任务批次', icon: 'profile', permission: ['retryLog'] }
},
{
path: '/job/batch/info',
name: 'JobBatchInfo',
hidden: true,
component: () => import('@/views/job/JobBatchInfo'),
meta: { title: '任务批次详情', icon: 'profile', permission: ['retryLog'] }
},
{
path: '/job/task/list',
name: 'JobTask',
component: () => import('@/views/job/JobTask'),
name: 'JobTaskList',
hidden: true,
component: () => import('@/views/job/JobTaskList'),
meta: { title: '任务项', icon: 'profile', permission: ['retryLog'] }
},
{
path: '/job/log/list',
name: 'JobLogMessageList',
hidden: true,
component: () => import('@/views/job/JobLogMessageList'),
meta: { title: '任务调度日志', icon: 'profile', permission: ['retryLog'] }
}
]
},

149
frontend/src/utils/enum.js Normal file
View File

@ -0,0 +1,149 @@
const enums = {
jobStatusEnum: {
'0': {
'name': '关闭',
'color': '#9c1f1f'
},
'1': {
'name': '开启',
'color': '#f5a22d'
}
},
taskType: {
'1': {
'name': '集群模式',
'color': '#d06892'
},
'2': {
'name': '广播模式',
'color': '#f5a22d'
},
'3': {
'name': '分片模式',
'color': '#e1f52d'
}
},
triggerType: {
'1': {
'name': 'CRON表达式',
'color': '#d06892'
},
'2': {
'name': '固定时间',
'color': '#f5a22d'
}
},
blockStrategy: {
'1': {
'name': '丢弃策略',
'color': '#d06892'
},
'2': {
'name': '覆盖',
'color': '#f5a22d'
},
'3': {
'name': '并行',
'color': '#e1f52d'
}
},
executorType: {
'1': {
'name': 'Java',
'color': '#d06892'
}
},
routeKey: {
'4': {
'name': '轮询',
'color': '#8f68d2'
},
'1': {
'name': '一致性Hash',
'color': '#d06892'
},
'2': {
'name': '随机',
'color': '#f5a22d'
},
'3': {
'name': 'LRU',
'color': '#e1f52d'
}
},
taskStatus: {
'1': {
'name': '待处理',
'color': '#64a6ea'
},
'2': {
'name': '运行中',
'color': '#1b7ee5'
},
'3': {
'name': '成功',
'color': '#087da1'
},
'4': {
'name': '失败',
'color': '#f52d80'
},
'5': {
'name': '停止',
'color': '#ac2df5'
},
'6': {
'name': '取消',
'color': '#f5732d'
}
},
operationReason: {
'0': {
'name': ''
},
'1': {
'name': '执行超时',
'color': '#64a6ea'
},
'2': {
'name': '无客户端节点',
'color': '#1b7ee5'
},
'3': {
'name': '任务已关闭',
'color': '#087da1'
}
// '4': {
// 'name': '失败',
// 'color': '#f52d80'
// },
// '5': {
// 'name': '停止',
// 'color': '#ac2df5'
// },
// '6': {
// 'name': '取消',
// 'color': '#f5732d'
// }
},
executeStatus: {
'2': {
'name': '运行中',
'color': '#1b7ee5'
},
'3': {
'name': '成功',
'color': '#087da1'
},
'4': {
'name': '失败',
'color': '#f52d80'
},
'5': {
'name': '停止',
'color': '#ac2df5'
}
}
}
module.exports = enums

View File

@ -0,0 +1,80 @@
<template>
<div>
<page-header-wrapper @back="() => $router.go(-1)" style="margin: -24px -1px 0">
<div></div>
</page-header-wrapper>
<a-card :bordered="false" v-if="jobBatchInfo !==null ">
<a-descriptions title="" :column="5" bordered>
<a-descriptions-item label="组名称">
{{ jobBatchInfo.groupName }}
</a-descriptions-item>
<a-descriptions-item label="任务名称">
{{ jobBatchInfo.jobName }}
</a-descriptions-item>
<a-descriptions-item label="重试状态">
<a-tag :color="taskStatus[jobBatchInfo.taskStatus].color">
{{ taskStatus[jobBatchInfo.taskStatus].name }}
</a-tag>
</a-descriptions-item>
<a-descriptions-item label="更新时间">
{{ jobBatchInfo.updateDt }}
</a-descriptions-item>
<a-descriptions-item label="执行器名称" span="3">
{{ jobBatchInfo.executorName }}
</a-descriptions-item>
</a-descriptions>
</a-card>
<div style="margin: 20px 0; border-left: #f5222d 5px solid; font-size: medium; font-weight: bold">
&nbsp;&nbsp; 任务项列表
</div>
<JobTaskList ref="JobTaskListRef" />
</div>
</template>
<script>
import { jobBatchDetail, jobTaskList } from '@/api/jobApi'
import moment from 'moment'
import enums from '@/utils/enum'
import JobTaskList from './JobTaskList'
export default {
name: 'JobInfo',
components: {
JobTaskList
},
data () {
return {
jobBatchInfo: null,
taskStatus: enums.taskStatus,
operationReason: enums.operationReason
}
},
created () {
const id = this.$route.query.id
const groupName = this.$route.query.groupName
if (id && groupName) {
jobBatchDetail(id).then(res => {
this.jobBatchInfo = res.data
this.queryParam = {
groupName: this.jobBatchInfo.groupName,
taskBatchId: id
}
this.$refs.JobTaskListRef.refreshTable(this.queryParam)
})
} else {
this.$router.push({ path: '/404' })
}
},
methods: {
jobTaskList,
parseDate (date) {
return moment(date).format('YYYY-MM-DD HH:mm:ss')
}
}
}
</script>
<style scoped>
</style>

View File

@ -66,8 +66,6 @@
</a-form>
</div>
<div class="table-operator">
<a-button type="primary" icon="plus" @click="handleNew()">新增</a-button>
<!-- <a-button type="primary" icon="plus" @click="handleBatchNew()">批量</a-button>-->
<a-dropdown v-action:edit v-if="selectedRowKeys.length > 0">
<a-menu slot="overlay" @click="onClick">
<a-menu-item key="1"><a-icon type="delete" />删除</a-menu-item>
@ -89,31 +87,13 @@
<span slot="serial" slot-scope="text, record">
{{ record.id }}
</span>
<span slot="taskType" slot-scope="text">
<a-tag :color="taskType[text].color">
{{ taskType[text].name }}
</a-tag>
</span>
<span slot="taskStatus" slot-scope="text">
<a-tag :color="taskStatus[text].color">
{{ taskStatus[text].name }}
</a-tag>
</span>
<span slot="triggerType" slot-scope="text">
<a-tag :color="triggerType[text].color">
{{ triggerType[text].name }}
</a-tag>
</span>
<span slot="blockStrategy" slot-scope="text">
<a-tag :color="blockStrategy[text].color">
{{ blockStrategy[text].name }}
</a-tag>
</span>
<span slot="triggerInterval" slot-scope="text">
<span>{{ text }}()</span>
</span>
<span slot="executorTimeout" slot-scope="text">
<span>{{ text }}()</span>
<span slot="operationReason" slot-scope="text">
{{ operationReason[text].name }}
</span>
<span slot="action" slot-scope="text, record">
<template>
@ -168,9 +148,10 @@ import AInput from 'ant-design-vue/es/input/Input'
import { STable } from '@/components'
import { jobBatchList } from '@/api/jobApi'
import { getAllGroupNameList } from '@/api/manage'
const enums = require('@/utils/enum')
export default {
name: 'JobList',
name: 'JobBatchList',
components: {
AInput,
ATextarea,
@ -186,54 +167,8 @@ export default {
advanced: false,
//
queryParam: {},
jobStatus: {
'0': {
'name': '关闭',
'color': '#9c1f1f'
},
'1': {
'name': '开启',
'color': '#f5a22d'
}
},
taskType: {
'1': {
'name': '集群模式',
'color': '#d06892'
},
'2': {
'name': '广播模式',
'color': '#f5a22d'
},
'3': {
'name': '分片模式',
'color': '#e1f52d'
}
},
triggerType: {
'1': {
'name': 'CRON表达式',
'color': '#d06892'
},
'2': {
'name': '固定时间',
'color': '#f5a22d'
}
},
blockStrategy: {
'1': {
'name': '丢弃策略',
'color': '#d06892'
},
'2': {
'name': '覆盖',
'color': '#f5a22d'
},
'3': {
'name': '并行',
'color': '#e1f52d'
}
},
taskStatus: enums.taskStatus,
operationReason: enums.operationReason,
//
columns: [
{
@ -242,42 +177,27 @@ export default {
},
{
title: '组名称',
dataIndex: 'groupName'
},
{
title: '任务名称',
dataIndex: 'jobName',
dataIndex: 'groupName',
ellipsis: true
},
// {
// title: '',
// dataIndex: 'jobName',
// ellipsis: true
// },
{
title: '状态',
dataIndex: 'taskStatus',
scopedSlots: { customRender: 'taskStatus' }
},
{
title: '任务类型',
dataIndex: 'taskType',
scopedSlots: { customRender: 'taskType' }
title: '开始执行时间',
dataIndex: 'executionAt'
},
{
title: '触发类型',
dataIndex: 'triggerType',
scopedSlots: { customRender: 'triggerType' }
},
{
title: '间隔时长',
dataIndex: 'triggerInterval',
scopedSlots: { customRender: 'triggerInterval' }
},
{
title: '阻塞策略',
dataIndex: 'blockStrategy',
scopedSlots: { customRender: 'blockStrategy' }
},
{
title: '超时时间',
dataIndex: 'executorTimeout',
scopedSlots: { customRender: 'executorTimeout' }
title: '操作原因',
dataIndex: 'operationReason',
scopedSlots: { customRender: 'operationReason' }
},
{
title: '创建时间',
@ -343,7 +263,7 @@ export default {
this.advanced = !this.advanced
},
handleInfo (record) {
this.$router.push({ path: '/job/info', query: { id: record.id, groupName: record.groupName } })
this.$router.push({ path: '/job/batch/info', query: { id: record.id, groupName: record.groupName } })
},
handleOk (record) {},
handleSuspend (record) {

View File

@ -4,25 +4,58 @@
<div></div>
</page-header-wrapper>
<a-card :bordered="false" v-if="jobInfo !==null ">
<a-descriptions title="" bordered>
<a-descriptions title="" :column="4" bordered>
<a-descriptions-item label="组名称">
{{ jobInfo.groupName }}
</a-descriptions-item>
<a-descriptions-item label="任务名称">
{{ jobInfo.jobName }}
</a-descriptions-item>
<a-descriptions-item label="重试次数">
{{ jobInfo.retryCount }}
</a-descriptions-item>
<a-descriptions-item label="重试状态 | 数据类型">
<a-tag color="red">
{{ retryStatus[jobInfo.retryStatus] }}
<a-descriptions-item label="触发类型">
<a-tag :color="triggerType[jobInfo.triggerType].color">
{{ triggerType[jobInfo.triggerType].name }}
</a-tag>
<a-divider type="vertical" />
</a-descriptions-item>
<a-descriptions-item label="间隔时长">
{{ jobInfo.triggerInterval }}
</a-descriptions-item>
<a-descriptions-item label="最大重试次数">
{{ jobInfo.maxRetryTimes }}
</a-descriptions-item>
<a-descriptions-item label="重试间隔">
{{ jobInfo.retryInterval }}()
</a-descriptions-item>
<a-descriptions-item label="并行数">
{{ jobInfo.parallelNum }}
</a-descriptions-item>
<a-descriptions-item label="执行器类型">
<a-tag :color="routeKey[jobInfo.routeKey].color">
{{ routeKey[jobInfo.routeKey].name }}
</a-tag>
</a-descriptions-item>
<a-descriptions-item label="执行器类型">
<a-tag :color="executorType[jobInfo.executorType].color">
{{ executorType[jobInfo.executorType].name }}
</a-tag>
</a-descriptions-item>
<a-descriptions-item label="任务类型">
<a-tag :color="taskType[jobInfo.taskType].color">
{{ taskType[jobInfo.taskType].name }}
</a-tag>
</a-descriptions-item>
<a-descriptions-item label="阻塞策略">
<a-tag :color="blockStrategy[jobInfo.blockStrategy].color">
{{ blockStrategy[jobInfo.blockStrategy].name }}
</a-tag>
</a-descriptions-item>
<a-descriptions-item label="重试状态">
<a-tag :color="jobStatusEnum[jobInfo.jobStatus].color">
{{ jobStatusEnum[jobInfo.jobStatus].name }}
</a-tag>
</a-descriptions-item>
<a-descriptions-item label="超时时间">
{{ jobInfo.executorTimeout }}()
</a-descriptions-item>
<a-descriptions-item label="下次触发时间">
{{ jobInfo.nextTriggerAt }}
</a-descriptions-item>
@ -46,6 +79,7 @@
<script>
import { getJobDetail } from '@/api/jobApi'
import moment from 'moment'
import enums from '@/utils/enum'
export default {
name: 'JobInfo',
@ -55,22 +89,12 @@ export default {
data () {
return {
jobInfo: null,
retryStatus: {
'0': '处理中',
'1': '处理成功',
'2': '最大次数',
'3': '暂停'
},
taskType: {
'1': {
'name': '重试数据',
'color': '#d06892'
},
'2': {
'name': '回调数据',
'color': '#f5a22d'
}
}
jobStatusEnum: enums.jobStatusEnum,
taskType: enums.taskType,
triggerType: enums.triggerType,
blockStrategy: enums.blockStrategy,
executorType: enums.executorType,
routeKey: enums.routeKey
}
},
created () {

View File

@ -95,8 +95,8 @@
</a-tag>
</span>
<span slot="jobStatus" slot-scope="text">
<a-tag :color="jobStatus[text].color">
{{ jobStatus[text].name }}
<a-tag :color="jobStatusEnum[text].color">
{{ jobStatusEnum[text].name }}
</a-tag>
</span>
<span slot="triggerType" slot-scope="text">
@ -168,6 +168,7 @@ import AInput from 'ant-design-vue/es/input/Input'
import { STable } from '@/components'
import { getJobList } from '@/api/jobApi'
import { getAllGroupNameList } from '@/api/manage'
import enums from '@/utils/enum'
export default {
name: 'JobList',
@ -186,54 +187,11 @@ export default {
advanced: false,
//
queryParam: {},
jobStatus: {
'0': {
'name': '关闭',
'color': '#9c1f1f'
},
'1': {
'name': '开启',
'color': '#f5a22d'
}
},
taskType: {
'1': {
'name': '集群模式',
'color': '#d06892'
},
'2': {
'name': '广播模式',
'color': '#f5a22d'
},
'3': {
'name': '分片模式',
'color': '#e1f52d'
}
},
triggerType: {
'1': {
'name': 'CRON表达式',
'color': '#d06892'
},
'2': {
'name': '固定时间',
'color': '#f5a22d'
}
},
blockStrategy: {
'1': {
'name': '丢弃策略',
'color': '#d06892'
},
'2': {
'name': '覆盖',
'color': '#f5a22d'
},
'3': {
'name': '并行',
'color': '#e1f52d'
}
},
jobStatusEnum: enums.jobStatusEnum,
taskType: enums.taskType,
triggerType: enums.triggerType,
blockStrategy: enums.blockStrategy,
executorType: enums.executorType,
//
columns: [
{

View File

@ -0,0 +1,81 @@
<template>
<div>
<a-card>
<s-table
ref="table"
size="default"
rowKey="key"
:columns="columns"
:data="loadData"
>
<span slot="serial" slot-scope="text, record">
{{ record.id }}
</span>
</s-table>
</a-card>
</div>
</template>
<script>
import moment from 'moment'
import { STable } from '@/components'
import { jobLogList } from '@/api/jobApi'
export default {
name: 'JobLogList',
components: {
STable
},
data () {
return {
//
columns: [
{
title: '#',
scopedSlots: { customRender: 'serial' },
width: '5%'
},
{
title: '客户端地址',
dataIndex: 'clientAddress',
width: '10%'
},
{
title: '信息',
dataIndex: 'message',
width: '50%'
},
{
title: '触发时间',
dataIndex: 'createDt',
sorter: true,
customRender: (text) => moment(text).format('YYYY-MM-DD HH:mm:ss'),
width: '10%'
}
],
queryParam: {},
// Promise
loadData: parameter => {
return jobLogList(Object.assign(parameter, this.queryParam))
.then(res => {
this.total = res.total
return res
})
},
total: 0
}
},
methods: {
refreshTable (v) {
this.queryParam = v
this.$refs.table.refresh(true)
}
}
}
</script>
<style scoped>
</style>

View File

@ -1,445 +0,0 @@
<template>
<a-card :bordered="false">
<div class="table-page-search-wrapper">
<a-form layout="inline">
<a-row :gutter="48">
<a-col :md="8" :sm="24">
<a-form-item label="组名称">
<a-select
v-model="queryParam.groupName"
placeholder="请输入组名称"
@change="(value) => handleChange(value)"
>
<a-select-option v-for="item in groupNameList" :value="item" :key="item">{{ item }}</a-select-option>
</a-select>
</a-form-item>
</a-col>
<a-col :md="8" :sm="24">
<a-form-item label="场景名称">
<a-select v-model="queryParam.sceneName" placeholder="请选择场景名称" allowClear>
<a-select-option v-for="item in sceneList" :value="item.sceneName" :key="item.sceneName">
{{ item.sceneName }}</a-select-option
>
</a-select>
</a-form-item>
</a-col>
<a-col :md="8" :sm="24">
<a-form-item label="状态">
<a-select v-model="queryParam.jobStatus" placeholder="请选择状态" allowClear>
<a-select-option v-for="(index, value) in jobStatus" :value="value" :key="value">
{{ index.name }}</a-select-option
>
</a-select>
</a-form-item>
</a-col>
<template v-if="advanced">
<a-col :md="8" :sm="24">
<a-form-item label="业务编号">
<a-input v-model="queryParam.bizNo" placeholder="请输入业务编号" allowClear />
</a-form-item>
</a-col>
<a-col :md="8" :sm="24">
<a-form-item label="幂等id">
<a-input v-model="queryParam.idempotentId" placeholder="请输入幂等id" allowClear />
</a-form-item>
</a-col>
<a-col :md="8" :sm="24">
<a-form-item label="UniqueId">
<a-input v-model="queryParam.uniqueId" placeholder="请输入唯一id" allowClear/>
</a-form-item>
</a-col>
</template>
<a-col :md="(!advanced && 8) || 24" :sm="24">
<span
class="table-page-search-submitButtons"
:style="(advanced && { float: 'right', overflow: 'hidden' }) || {}"
>
<a-button type="primary" @click="$refs.table.refresh(true)">查询</a-button>
<a-button style="margin-left: 8px" @click="() => (queryParam = {})">重置</a-button>
<a @click="toggleAdvanced" style="margin-left: 8px">
{{ advanced ? '收起' : '展开' }}
<a-icon :type="advanced ? 'up' : 'down'" />
</a>
</span>
</a-col>
</a-row>
</a-form>
</div>
<div class="table-operator">
<a-button type="primary" icon="plus" @click="handleNew()">新增</a-button>
<!-- <a-button type="primary" icon="plus" @click="handleBatchNew()">批量</a-button>-->
<a-dropdown v-action:edit v-if="selectedRowKeys.length > 0">
<a-menu slot="overlay" @click="onClick">
<a-menu-item key="1"><a-icon type="delete" />删除</a-menu-item>
<a-menu-item key="2"><a-icon type="edit" />更新</a-menu-item>
</a-menu>
<a-button style="margin-left: 8px"> 批量操作 <a-icon type="down" /> </a-button>
</a-dropdown>
</div>
<s-table
ref="table"
size="default"
:rowKey="(record) => record.id"
:columns="columns"
:data="loadData"
:alert="options.alert"
:rowSelection="options.rowSelection"
>
<span slot="serial" slot-scope="text, record">
{{ record.id }}
</span>
<span slot="taskType" slot-scope="text">
<a-tag :color="taskType[text].color">
{{ taskType[text].name }}
</a-tag>
</span>
<span slot="jobStatus" slot-scope="text">
<a-tag :color="jobStatus[text].color">
{{ jobStatus[text].name }}
</a-tag>
</span>
<span slot="triggerType" slot-scope="text">
<a-tag :color="triggerType[text].color">
{{ triggerType[text].name }}
</a-tag>
</span>
<span slot="blockStrategy" slot-scope="text">
<a-tag :color="blockStrategy[text].color">
{{ blockStrategy[text].name }}
</a-tag>
</span>
<span slot="triggerInterval" slot-scope="text">
<span>{{ text }}()</span>
</span>
<span slot="executorTimeout" slot-scope="text">
<span>{{ text }}()</span>
</span>
<span slot="action" slot-scope="text, record">
<template>
<a @click="handleInfo(record)">详情</a>
<a-divider type="vertical" />
<a-popconfirm
title="是否暂停?"
ok-text="恢复"
cancel-text="取消"
@confirm="handleSuspend(record)"
>
<a href="javascript:;" v-if="record.retryStatus === 0">暂停</a>
</a-popconfirm>
<a-divider type="vertical" v-if="record.retryStatus === 0" />
<a-popconfirm
title="是否恢复?"
ok-text="恢复"
cancel-text="取消"
@confirm="handleRecovery(record)"
>
<a href="javascript:;" v-if="record.retryStatus === 3">恢复</a>
</a-popconfirm>
<a-divider type="vertical" v-if="record.retryStatus === 3" />
<a-popconfirm
title="是否完成?"
ok-text="完成"
cancel-text="取消"
@confirm="handleFinish(record)"
>
<a href="javascript:;" v-if="record.retryStatus !== 1 && record.retryStatus !== 2">完成</a>
</a-popconfirm>
<a-divider type="vertical" v-if="record.retryStatus !== 1 && record.retryStatus !== 2" />
<a-popconfirm
title="是否执行任务?"
ok-text="执行"
cancel-text="取消"
@confirm="handleTrigger(record)"
>
<a href="javascript:;" v-if="record.retryStatus !== 1 && record.retryStatus !== 2">执行</a>
</a-popconfirm>
</template>
</span>
</s-table>
</a-card>
</template>
<script>
import ATextarea from 'ant-design-vue/es/input/TextArea'
import AInput from 'ant-design-vue/es/input/Input'
import { STable } from '@/components'
import { getJobList } from '@/api/jobApi'
import { getAllGroupNameList } from '@/api/manage'
export default {
name: 'JobList',
components: {
AInput,
ATextarea,
STable
},
data () {
return {
currentComponet: 'List',
record: '',
mdl: {},
visible: false,
// /
advanced: false,
//
queryParam: {},
jobStatus: {
'0': {
'name': '关闭',
'color': '#9c1f1f'
},
'1': {
'name': '开启',
'color': '#f5a22d'
}
},
taskType: {
'1': {
'name': '集群模式',
'color': '#d06892'
},
'2': {
'name': '广播模式',
'color': '#f5a22d'
},
'3': {
'name': '分片模式',
'color': '#e1f52d'
}
},
triggerType: {
'1': {
'name': 'CRON表达式',
'color': '#d06892'
},
'2': {
'name': '固定时间',
'color': '#f5a22d'
}
},
blockStrategy: {
'1': {
'name': '丢弃策略',
'color': '#d06892'
},
'2': {
'name': '覆盖',
'color': '#f5a22d'
},
'3': {
'name': '并行',
'color': '#e1f52d'
}
},
//
columns: [
{
title: 'ID',
scopedSlots: { customRender: 'serial' }
},
{
title: '组名称',
dataIndex: 'groupName'
},
{
title: '任务名称',
dataIndex: 'jobName',
ellipsis: true
},
{
title: '触发时间',
dataIndex: 'nextTriggerAt'
},
{
title: '状态',
dataIndex: 'jobStatus',
scopedSlots: { customRender: 'jobStatus' }
},
{
title: '任务类型',
dataIndex: 'taskType',
scopedSlots: { customRender: 'taskType' }
},
{
title: '触发类型',
dataIndex: 'triggerType',
scopedSlots: { customRender: 'triggerType' }
},
{
title: '间隔时长',
dataIndex: 'triggerInterval',
scopedSlots: { customRender: 'triggerInterval' }
},
{
title: '阻塞策略',
dataIndex: 'blockStrategy',
scopedSlots: { customRender: 'blockStrategy' }
},
{
title: '超时时间',
dataIndex: 'executorTimeout',
scopedSlots: { customRender: 'executorTimeout' }
},
{
title: '更新时间',
dataIndex: 'updateDt',
sorter: true,
width: '10%'
},
{
title: '操作',
fixed: 'right',
dataIndex: 'action',
width: '180px',
scopedSlots: { customRender: 'action' }
}
],
// Promise
loadData: (parameter) => {
return getJobList(Object.assign(parameter, this.queryParam)).then((res) => {
return res
})
},
selectedRowKeys: [],
selectedRows: [],
// custom table alert & rowSelection
options: {
alert: {
show: true,
clear: () => {
this.selectedRowKeys = []
}
},
rowSelection: {
selectedRowKeys: this.selectedRowKeys,
onChange: this.onSelectChange
}
},
optionAlertShow: false,
groupNameList: [],
sceneList: []
}
},
created () {
getAllGroupNameList().then((res) => {
this.groupNameList = res.data
if (this.groupNameList !== null && this.groupNameList.length > 0) {
this.queryParam['groupName'] = this.groupNameList[0]
this.$refs.table.refresh(true)
this.handleChange(this.groupNameList[0])
}
})
},
methods: {
handleNew () {
this.$refs.saveRetryTask.isShow(true, null)
},
handleBatchNew () {
this.$refs.batchSaveRetryTask.isShow(true, null)
},
handleChange (value) {
},
toggleAdvanced () {
this.advanced = !this.advanced
},
handleInfo (record) {
this.$router.push({ path: '/job/info', query: { id: record.id, groupName: record.groupName } })
},
handleOk (record) {},
handleSuspend (record) {
// updateRetryTaskStatus({ id: record.id, groupName: record.groupName, retryStatus: 3 }).then((res) => {
// const { status } = res
// if (status === 0) {
// this.$message.error('')
// } else {
// this.$refs.table.refresh(true)
// this.$message.success('')
// }
// })
},
handleRecovery (record) {
// updateRetryTaskStatus({ id: record.id, groupName: record.groupName, retryStatus: 0 }).then((res) => {
// const { status } = res
// if (status === 0) {
// this.$message.error('')
// } else {
// this.$refs.table.refresh(true)
// this.$message.success('')
// }
// })
},
handleFinish (record) {
// updateRetryTaskStatus({ id: record.id, groupName: record.groupName, retryStatus: 1 }).then((res) => {
// const { status } = res
// if (status === 0) {
// this.$message.error('')
// } else {
// this.$refs.table.refresh(true)
// this.$message.success('')
// }
// })
},
handleTrigger (record) {
// if (record.taskType === 1) {
// manualTriggerRetryTask({ groupName: record.groupName, uniqueIds: [ record.uniqueId ] }).then(res => {
// const { status } = res
// if (status === 0) {
// this.$message.error('')
// } else {
// this.$refs.table.refresh(true)
// this.$message.success('')
// }
// })
// } else {
// manualTriggerCallbackTask({ groupName: record.groupName, uniqueIds: [ record.uniqueId ] }).then(res => {
// const { status } = res
// if (status === 0) {
// this.$message.error('')
// } else {
// this.$refs.table.refresh(true)
// this.$message.success('')
// }
// })
// }
},
refreshTable (v) {
this.$refs.table.refresh(true)
},
onSelectChange (selectedRowKeys, selectedRows) {
this.selectedRowKeys = selectedRowKeys
this.selectedRows = selectedRows
},
handlerDel () {
// var that = this
// this.$confirm({
// title: '?',
// content: h => <div style="color:red;">!</div>,
// onOk () {
// batchDelete({ groupName: that.selectedRows[0].groupName, ids: that.selectedRowKeys }).then(res => {
// that.$refs.table.refresh(true)
// that.$message.success(`${res.data}`)
// that.selectedRowKeys = []
// })
// },
// onCancel () {
// },
// class: 'test'
// })
},
onClick ({ key }) {
if (key === '2') {
this.$refs.batchUpdateRetryTaskInfo.isShow(true, this.selectedRows, this.selectedRowKeys)
return
}
if (key === '1') {
this.handlerDel()
}
}
}
}
</script>

View File

@ -0,0 +1,325 @@
<template>
<a-card :bordered="false">
<div class="table-page-search-wrapper">
<a-form layout="inline">
<a-row :gutter="48">
<!-- <a-col :md="8" :sm="24">-->
<!-- <a-form-item label="组名称">-->
<!-- <a-select-->
<!-- v-model="queryParam.groupName"-->
<!-- placeholder="请输入组名称"-->
<!-- @change="(value) => handleChange(value)"-->
<!-- >-->
<!-- <a-select-option v-for="item in groupNameList" :value="item" :key="item">{{ item }}</a-select-option>-->
<!-- </a-select>-->
<!-- </a-form-item>-->
<!-- </a-col>-->
<!-- <a-col :md="8" :sm="24">-->
<!-- <a-form-item label="场景名称">-->
<!-- <a-select v-model="queryParam.sceneName" placeholder="请选择场景名称" allowClear>-->
<!-- <a-select-option v-for="item in sceneList" :value="item.sceneName" :key="item.sceneName">-->
<!-- {{ item.sceneName }}</a-select-option-->
<!-- >-->
<!-- </a-select>-->
<!-- </a-form-item>-->
<!-- </a-col>-->
<!-- <a-col :md="8" :sm="24">-->
<!-- <a-form-item label="状态">-->
<!-- <a-select v-model="queryParam.jobStatus" placeholder="请选择状态" allowClear>-->
<!-- <a-select-option v-for="(index, value) in jobStatus" :value="value" :key="value">-->
<!-- {{ index.name }}</a-select-option-->
<!-- >-->
<!-- </a-select>-->
<!-- </a-form-item>-->
<!-- </a-col>-->
<!-- <template v-if="advanced">-->
<!-- <a-col :md="8" :sm="24">-->
<!-- <a-form-item label="业务编号">-->
<!-- <a-input v-model="queryParam.bizNo" placeholder="请输入业务编号" allowClear />-->
<!-- </a-form-item>-->
<!-- </a-col>-->
<!-- <a-col :md="8" :sm="24">-->
<!-- <a-form-item label="幂等id">-->
<!-- <a-input v-model="queryParam.idempotentId" placeholder="请输入幂等id" allowClear />-->
<!-- </a-form-item>-->
<!-- </a-col>-->
<!-- <a-col :md="8" :sm="24">-->
<!-- <a-form-item label="UniqueId">-->
<!-- <a-input v-model="queryParam.uniqueId" placeholder="请输入唯一id" allowClear/>-->
<!-- </a-form-item>-->
<!-- </a-col>-->
<!-- </template>-->
<!-- <a-col :md="(!advanced && 8) || 24" :sm="24">-->
<!-- <span-->
<!-- class="table-page-search-submitButtons"-->
<!-- :style="(advanced && { float: 'right', overflow: 'hidden' }) || {}"-->
<!-- >-->
<!-- <a-button type="primary" @click="$refs.table.refresh(true)">查询</a-button>-->
<!-- <a-button style="margin-left: 8px" @click="() => (queryParam = {})">重置</a-button>-->
<!-- <a @click="toggleAdvanced" style="margin-left: 8px">-->
<!-- {{ advanced ? '收起' : '展开' }}-->
<!-- <a-icon :type="advanced ? 'up' : 'down'" />-->
<!-- </a>-->
<!-- </span>-->
<!-- </a-col>-->
</a-row>
</a-form>
</div>
<div class="table-operator">
<a-dropdown v-action:edit v-if="selectedRowKeys.length > 0">
<a-menu slot="overlay" @click="onClick">
<a-menu-item key="1"><a-icon type="delete" />删除</a-menu-item>
<a-menu-item key="2"><a-icon type="edit" />更新</a-menu-item>
</a-menu>
<a-button style="margin-left: 8px"> 批量操作 <a-icon type="down" /> </a-button>
</a-dropdown>
</div>
<s-table
ref="table"
size="default"
:rowKey="(record) => record.id"
:columns="columns"
:data="loadData"
:alert="options.alert"
:rowSelection="options.rowSelection"
>
<span slot="serial" slot-scope="text, record">
{{ record.id }}
</span>
<span slot="executeStatus" slot-scope="text">
<a-tag :color="executeStatus[text].color">
{{ executeStatus[text].name }}
</a-tag>
</span>
<p slot="expandedRowRender" style="margin: 0" slot-scope="record">
执行结果: {{ record.resultMessage }}<br/>
参数: {{ record.argsStr }}
</p>
<span slot="action" slot-scope="text, record">
<template>
<a @click="handleLog(record)">日志</a>
</template>
</span>
</s-table>
</a-card>
</template>
<script>
import ATextarea from 'ant-design-vue/es/input/TextArea'
import AInput from 'ant-design-vue/es/input/Input'
import { STable } from '@/components'
import { jobTaskList } from '@/api/jobApi'
import { getAllGroupNameList } from '@/api/manage'
import enums from '@/utils/enum'
import JobLogMessageList from './JobLogMessageList'
export default {
name: 'JobTaskList',
components: {
AInput,
ATextarea,
STable,
JobLogMessageList
},
data () {
return {
currentComponet: 'List',
record: '',
mdl: {},
visible: false,
// /
advanced: false,
//
queryParam: {},
executeStatus: enums.executeStatus,
//
columns: [
{
title: 'ID',
scopedSlots: { customRender: 'serial' }
},
{
title: '组名称',
dataIndex: 'groupName'
},
{
title: '参数',
dataIndex: 'argsStr',
ellipsis: true
},
{
title: '结果',
dataIndex: 'resultMessage',
ellipsis: true
},
{
title: '状态',
dataIndex: 'executeStatus',
scopedSlots: { customRender: 'executeStatus' }
},
{
title: '重试次数',
dataIndex: 'retryCount'
},
{
title: '开始执行时间',
dataIndex: 'createDt',
sorter: true,
width: '10%'
},
{
title: '操作',
fixed: 'right',
dataIndex: 'action',
width: '180px',
scopedSlots: { customRender: 'action' }
}
],
// Promise
loadData: (parameter) => {
return jobTaskList(Object.assign(parameter, this.queryParam)).then((res) => {
return res
})
},
selectedRowKeys: [],
selectedRows: [],
// custom table alert & rowSelection
options: {
alert: {
show: true,
clear: () => {
this.selectedRowKeys = []
}
},
rowSelection: {
selectedRowKeys: this.selectedRowKeys,
onChange: this.onSelectChange
}
},
optionAlertShow: false,
groupNameList: [],
sceneList: []
}
},
created () {
getAllGroupNameList().then((res) => {
this.groupNameList = res.data
if (this.groupNameList !== null && this.groupNameList.length > 0) {
this.queryParam['groupName'] = this.groupNameList[0]
this.$refs.table.refresh(true)
this.handleChange(this.groupNameList[0])
}
})
},
methods: {
handleNew () {
this.$refs.saveRetryTask.isShow(true, null)
},
handleBatchNew () {
this.$refs.batchSaveRetryTask.isShow(true, null)
},
handleChange (value) {
},
toggleAdvanced () {
this.advanced = !this.advanced
},
handleLog (record) {
this.$router.push({ path: '/job/log/list', query: { taskBatchId: record.id, jobId: record.jobId } })
},
handleOk (record) {},
handleSuspend (record) {
// updateRetryTaskStatus({ id: record.id, groupName: record.groupName, retryStatus: 3 }).then((res) => {
// const { status } = res
// if (status === 0) {
// this.$message.error('')
// } else {
// this.$refs.table.refresh(true)
// this.$message.success('')
// }
// })
},
handleRecovery (record) {
// updateRetryTaskStatus({ id: record.id, groupName: record.groupName, retryStatus: 0 }).then((res) => {
// const { status } = res
// if (status === 0) {
// this.$message.error('')
// } else {
// this.$refs.table.refresh(true)
// this.$message.success('')
// }
// })
},
handleFinish (record) {
// updateRetryTaskStatus({ id: record.id, groupName: record.groupName, retryStatus: 1 }).then((res) => {
// const { status } = res
// if (status === 0) {
// this.$message.error('')
// } else {
// this.$refs.table.refresh(true)
// this.$message.success('')
// }
// })
},
handleTrigger (record) {
// if (record.taskType === 1) {
// manualTriggerRetryTask({ groupName: record.groupName, uniqueIds: [ record.uniqueId ] }).then(res => {
// const { status } = res
// if (status === 0) {
// this.$message.error('')
// } else {
// this.$refs.table.refresh(true)
// this.$message.success('')
// }
// })
// } else {
// manualTriggerCallbackTask({ groupName: record.groupName, uniqueIds: [ record.uniqueId ] }).then(res => {
// const { status } = res
// if (status === 0) {
// this.$message.error('')
// } else {
// this.$refs.table.refresh(true)
// this.$message.success('')
// }
// })
// }
},
refreshTable (v) {
this.queryParam = v
this.$refs.table.refresh(true)
},
onSelectChange (selectedRowKeys, selectedRows) {
this.selectedRowKeys = selectedRowKeys
this.selectedRows = selectedRows
},
handlerDel () {
// var that = this
// this.$confirm({
// title: '?',
// content: h => <div style="color:red;">!</div>,
// onOk () {
// batchDelete({ groupName: that.selectedRows[0].groupName, ids: that.selectedRowKeys }).then(res => {
// that.$refs.table.refresh(true)
// that.$message.success(`${res.data}`)
// that.selectedRowKeys = []
// })
// },
// onCancel () {
// },
// class: 'test'
// })
},
onClick ({ key }) {
if (key === '2') {
this.$refs.batchUpdateRetryTaskInfo.isShow(true, this.selectedRows, this.selectedRowKeys)
return
}
if (key === '1') {
this.handlerDel()
}
}
}
}
</script>