This commit is contained in:
asp_ly 2024-12-14 22:56:04 +08:00
parent adb747f070
commit ccac93e4a8
15 changed files with 806 additions and 897 deletions

View File

@ -69,16 +69,14 @@ public class WorkflowDefinitionApiController extends BaseController<WorkflowDefi
@Operation(summary = "启动工作流实例")
@PostMapping("/start")
public Response<WorkflowInstanceCreateDTO> startWorkflow(
public Response<WorkflowInstanceDTO> startWorkflow(
@Parameter(description = "流程标识", required = true) @RequestParam String processKey,
@Parameter(description = "业务标识", required = true) @RequestParam String businessKey
) {
Map<String, Object> variables = new HashMap<>();
try {
// 同步创建实例立即返回实例ID
WorkflowInstanceCreateDTO result = workflowDefinitionService.startWorkflow(processKey, businessKey, variables);
return Response.success(result);
return Response.success(workflowDefinitionService.startWorkflow(processKey, businessKey, variables));
} catch (Exception e) {
log.error("Failed to start workflow", e);
return Response.error(ResponseCode.WORKFLOW_EXECUTION_ERROR);
@ -119,48 +117,49 @@ public class WorkflowDefinitionApiController extends BaseController<WorkflowDefi
WorkflowInstanceDTO instanceDTO = new WorkflowInstanceDTO();
// instanceDTO.setId(historicProcessInstance.getId());
instanceDTO.setProcessDefinitionId(historicProcessInstance.getProcessDefinitionId());
instanceDTO.setBusinessKey(historicProcessInstance.getBusinessKey());
instanceDTO.setStartTime(historicProcessInstance.getStartTime());
instanceDTO.setEndTime(historicProcessInstance.getEndTime());
instanceDTO.setDurationInMillis(historicProcessInstance.getDurationInMillis());
instanceDTO.setStartUserId(historicProcessInstance.getStartUserId());
instanceDTO.setStatus(historicProcessInstance.getEndTime() != null ? WorkflowInstanceStatusEnums.COMPLETED : WorkflowInstanceStatusEnums.RUNNING);
instanceDTO.setVariables(historicProcessInstance.getProcessVariables());
// 查询活动节点历史
List<HistoricActivityInstance> activities = historyService.createHistoricActivityInstanceQuery()
.processInstanceId(processInstanceId)
.orderByHistoricActivityInstanceStartTime()
.asc()
.list();
List<WorkflowInstanceDTO.ActivityInstance> activityInstances = activities.stream()
.map(activity -> {
WorkflowInstanceDTO.ActivityInstance activityInstance = new WorkflowInstanceDTO.ActivityInstance();
activityInstance.setId(activity.getId());
activityInstance.setActivityId(activity.getActivityId());
activityInstance.setActivityName(activity.getActivityName());
activityInstance.setActivityType(activity.getActivityType());
activityInstance.setStartTime(activity.getStartTime());
activityInstance.setEndTime(activity.getEndTime());
activityInstance.setDurationInMillis(activity.getDurationInMillis());
// 如果是Shell任务获取Shell相关变量
if ("serviceTask".equals(activity.getActivityType())) {
Map<String, Object> variables = historicProcessInstance.getProcessVariables();
activityInstance.setShellOutput((String) variables.get("shellOutput"));
activityInstance.setShellError((String) variables.get("shellError"));
activityInstance.setShellExitCode((Integer) variables.get("shellExitCode"));
}
return activityInstance;
})
.collect(Collectors.toList());
instanceDTO.setActivities(activityInstances);
return Response.success(instanceDTO);
// instanceDTO.setProcessDefinitionId(historicProcessInstance.getProcessDefinitionId());
// instanceDTO.setBusinessKey(historicProcessInstance.getBusinessKey());
// instanceDTO.setStartTime(historicProcessInstance.getStartTime());
// instanceDTO.setEndTime(historicProcessInstance.getEndTime());
// instanceDTO.setDurationInMillis(historicProcessInstance.getDurationInMillis());
// instanceDTO.setStartUserId(historicProcessInstance.getStartUserId());
// instanceDTO.setStatus(historicProcessInstance.getEndTime() != null ? WorkflowInstanceStatusEnums.COMPLETED : WorkflowInstanceStatusEnums.RUNNING);
// instanceDTO.setVariables(historicProcessInstance.getProcessVariables());
//
// // 查询活动节点历史
// List<HistoricActivityInstance> activities = historyService.createHistoricActivityInstanceQuery()
// .processInstanceId(processInstanceId)
// .orderByHistoricActivityInstanceStartTime()
// .asc()
// .list();
//
// List<WorkflowInstanceDTO.ActivityInstance> activityInstances = activities.stream()
// .map(activity -> {
// WorkflowInstanceDTO.ActivityInstance activityInstance = new WorkflowInstanceDTO.ActivityInstance();
// activityInstance.setId(activity.getId());
// activityInstance.setActivityId(activity.getActivityId());
// activityInstance.setActivityName(activity.getActivityName());
// activityInstance.setActivityType(activity.getActivityType());
// activityInstance.setStartTime(activity.getStartTime());
// activityInstance.setEndTime(activity.getEndTime());
// activityInstance.setDurationInMillis(activity.getDurationInMillis());
//
// // 如果是Shell任务获取Shell相关变量
// if ("serviceTask".equals(activity.getActivityType())) {
// Map<String, Object> variables = historicProcessInstance.getProcessVariables();
// activityInstance.setShellOutput((String) variables.get("shellOutput"));
// activityInstance.setShellError((String) variables.get("shellError"));
// activityInstance.setShellExitCode((Integer) variables.get("shellExitCode"));
// }
//
// return activityInstance;
// })
// .collect(Collectors.toList());
//
// instanceDTO.setActivities(activityInstances);
//
// return Response.success(instanceDTO);'
return Response.success();
}
@Operation(summary = "获取工作流执行状态")
@ -183,23 +182,24 @@ public class WorkflowDefinitionApiController extends BaseController<WorkflowDefi
.desc()
.list();
List<WorkflowInstanceDTO> instanceDTOs = historicProcessInstances.stream()
.map(historicProcessInstance -> {
WorkflowInstanceDTO instanceDTO = new WorkflowInstanceDTO();
// instanceDTO.setId(historicProcessInstance.getId());
instanceDTO.setProcessDefinitionId(historicProcessInstance.getProcessDefinitionId());
instanceDTO.setBusinessKey(historicProcessInstance.getBusinessKey());
instanceDTO.setStartTime(historicProcessInstance.getStartTime());
instanceDTO.setEndTime(historicProcessInstance.getEndTime());
instanceDTO.setDurationInMillis(historicProcessInstance.getDurationInMillis());
instanceDTO.setStartUserId(historicProcessInstance.getStartUserId());
instanceDTO.setStatus(historicProcessInstance.getEndTime() != null ? WorkflowInstanceStatusEnums.COMPLETED : WorkflowInstanceStatusEnums.RUNNING);
instanceDTO.setVariables(historicProcessInstance.getProcessVariables());
return instanceDTO;
})
.collect(Collectors.toList());
// List<WorkflowInstanceDTO> instanceDTOs = historicProcessInstances.stream()
// .map(historicProcessInstance -> {
// WorkflowInstanceDTO instanceDTO = new WorkflowInstanceDTO();
//// instanceDTO.setId(historicProcessInstance.getId());
// instanceDTO.setProcessDefinitionId(historicProcessInstance.getProcessDefinitionId());
// instanceDTO.setBusinessKey(historicProcessInstance.getBusinessKey());
// instanceDTO.setStartTime(historicProcessInstance.getStartTime());
// instanceDTO.setEndTime(historicProcessInstance.getEndTime());
// instanceDTO.setDurationInMillis(historicProcessInstance.getDurationInMillis());
// instanceDTO.setStartUserId(historicProcessInstance.getStartUserId());
// instanceDTO.setStatus(historicProcessInstance.getEndTime() != null ? WorkflowInstanceStatusEnums.COMPLETED : WorkflowInstanceStatusEnums.RUNNING);
// instanceDTO.setVariables(historicProcessInstance.getProcessVariables());
// return instanceDTO;
// })
// .collect(Collectors.toList());
return Response.success(instanceDTOs);
// return Response.success(instanceDTOs);
return Response.success();
}
@Operation(summary = "获取节点实时日志")

View File

@ -0,0 +1,15 @@
package com.qqchen.deploy.backend.workflow.converter;
import com.qqchen.deploy.backend.framework.converter.BaseConverter;
import com.qqchen.deploy.backend.workflow.dto.WorkflowDefinitionDTO;
import com.qqchen.deploy.backend.workflow.dto.WorkflowInstanceDTO;
import com.qqchen.deploy.backend.workflow.entity.WorkflowDefinition;
import com.qqchen.deploy.backend.workflow.entity.WorkflowInstance;
import org.mapstruct.Mapper;
/**
* 工作流定义转换器
*/
@Mapper(config = BaseConverter.class)
public interface WorkflowInstanceConverter extends BaseConverter<WorkflowInstance, WorkflowInstanceDTO> {
}

View File

@ -1,21 +1,47 @@
package com.qqchen.deploy.backend.workflow.dto;
import com.qqchen.deploy.backend.framework.dto.BaseDTO;
import com.qqchen.deploy.backend.workflow.enums.WorkflowInstanceStatusEnums;
import lombok.Data;
import java.time.LocalDateTime;
@Data
public class WorkflowInstanceCreateDTO extends BaseDTO {
private String processInstanceId;
private String processDefinitionKey;
private String businessKey;
private String status; // CREATING, RUNNING, ERROR
public static WorkflowInstanceCreateDTO of(String processInstanceId, String processDefinitionKey, String businessKey) {
WorkflowInstanceCreateDTO dto = new WorkflowInstanceCreateDTO();
dto.setProcessInstanceId(processInstanceId);
dto.setProcessDefinitionKey(processDefinitionKey);
dto.setBusinessKey(businessKey);
dto.setStatus("CREATING");
return dto;
}
/**
* 流程实例ID
*/
private String processInstanceId;
/**
* 流程定义ID
*/
private Long processDefinitionId;
/**
* 业务标识
*/
private String businessKey;
/**
* 实例状态
*/
private WorkflowInstanceStatusEnums status;
/**
* 流程变量(JSON)
*/
private String variables;
/**
* 开始时间
*/
private LocalDateTime startTime;
/**
* 结束时间
*/
private LocalDateTime endTime;
}

View File

@ -4,6 +4,8 @@ import com.qqchen.deploy.backend.framework.dto.BaseDTO;
import com.qqchen.deploy.backend.workflow.enums.WorkflowInstanceStatusEnums;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.List;
import java.util.Map;
@ -12,64 +14,39 @@ import java.util.Map;
@Schema(description = "工作流实例信息")
public class WorkflowInstanceDTO extends BaseDTO {
@Schema(description = "流程定义ID")
/**
* 流程实例ID
*/
private String processInstanceId;
/**
* 流程定义ID
*/
private String processDefinitionId;
@Schema(description = "业务标识")
/**
* 业务标识
*/
private String businessKey;
@Schema(description = "开始时间")
private Date startTime;
@Schema(description = "结束时间")
private Date endTime;
@Schema(description = "执行时长(毫秒)")
private Long durationInMillis;
@Schema(description = "启动用户ID")
private String startUserId;
@Schema(description = "状态(RUNNING/COMPLETED/FAILED)")
/**
* 实例状态
*/
private WorkflowInstanceStatusEnums status;
@Data
@Schema(description = "活动节点信息")
public static class ActivityInstance {
@Schema(description = "活动ID")
private String id;
@Schema(description = "活动定义ID")
private String activityId;
@Schema(description = "活动名称")
private String activityName;
@Schema(description = "活动类型")
private String activityType;
@Schema(description = "开始时间")
private Date startTime;
@Schema(description = "结束时间")
private Date endTime;
@Schema(description = "执行时长(毫秒)")
private Long durationInMillis;
@Schema(description = "Shell输出")
private String shellOutput;
@Schema(description = "Shell错误")
private String shellError;
@Schema(description = "Shell退出码")
private Integer shellExitCode;
}
@Schema(description = "活动节点列表")
private List<ActivityInstance> activities;
@Schema(description = "流程变量")
private Map<String, Object> variables;
/**
* 流程变量(JSON)
*/
private String variables;
/**
* 开始时间
*/
private LocalDateTime startTime;
/**
* 结束时间
*/
private LocalDateTime endTime;
}

View File

@ -36,6 +36,9 @@ public class WorkflowDefinition extends Entity<Long> {
*/
@Column(name = "`key`", nullable = false)
private String key;
@Column(name = "process_definition_id", nullable = false)
private String processDefinitionId;
/**
* 流程版本

View File

@ -30,7 +30,10 @@ public class WorkflowInstance extends Entity<Long> {
* 流程定义ID
*/
@Column(name = "process_definition_id", nullable = false)
private Long processDefinitionId;
private String processDefinitionId;
@Column(name = "workflow_definition_id", nullable = false)
private Long workflowDefinitionId;
/**
* 业务标识

View File

@ -4,6 +4,8 @@ import com.qqchen.deploy.backend.framework.repository.IBaseRepository;
import com.qqchen.deploy.backend.workflow.entity.WorkflowDefinition;
import org.springframework.stereotype.Repository;
import java.util.Optional;
/**
* 工作流定义仓库
*/
@ -18,4 +20,6 @@ public interface IWorkflowDefinitionRepository extends IBaseRepository<WorkflowD
* 检查流程标识是否存在
*/
boolean existsByKeyAndDeletedFalse(String key);
Optional<WorkflowDefinition> findByKey(String businessKey);
}

View File

@ -8,7 +8,7 @@ import java.util.List;
import java.util.Optional;
@Repository
public interface WorkflowInstanceRepository extends JpaRepository<WorkflowInstance, Long> {
public interface IWorkflowInstanceRepository extends JpaRepository<WorkflowInstance, Long> {
/**
* 根据Flowable流程实例ID查询工作流实例
@ -19,9 +19,5 @@ public interface WorkflowInstanceRepository extends JpaRepository<WorkflowInstan
* 根据业务标识查询工作流实例列表
*/
List<WorkflowInstance> findByBusinessKey(String businessKey);
/**
* 根据流程定义ID查询工作流实例列表
*/
List<WorkflowInstance> findByProcessDefinitionId(Long processDefinitionId);
}

View File

@ -5,7 +5,9 @@ import com.qqchen.deploy.backend.workflow.dto.WorkflowDefinitionDTO;
import com.qqchen.deploy.backend.workflow.dto.WorkflowDesignDTO;
import com.qqchen.deploy.backend.workflow.dto.WorkflowExecutionDTO;
import com.qqchen.deploy.backend.workflow.dto.WorkflowInstanceCreateDTO;
import com.qqchen.deploy.backend.workflow.dto.WorkflowInstanceDTO;
import com.qqchen.deploy.backend.workflow.entity.WorkflowDefinition;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.runtime.ProcessInstance;
import org.springframework.transaction.annotation.Transactional;
@ -24,7 +26,7 @@ public interface IWorkflowDefinitionService extends IBaseService<WorkflowDefinit
* @param dto 工作流定义DTO
* @return 工作流定义DTO
*/
void deployWorkflow(WorkflowDefinition workflowDefinition);
Deployment deployWorkflow(WorkflowDefinition workflowDefinition);
/**
* 启动工作流实例
@ -34,7 +36,7 @@ public interface IWorkflowDefinitionService extends IBaseService<WorkflowDefinit
* @param variables 流程变量
* @return 流程实例
*/
WorkflowInstanceCreateDTO startWorkflow(String processKey, String businessKey, Map<String, Object> variables);
WorkflowInstanceDTO startWorkflow(String processKey, String businessKey, Map<String, Object> variables);
/**
* 挂起工作流实例

View File

@ -14,10 +14,9 @@ public interface IWorkflowInstanceService {
* 创建工作流实例并关联Flowable实例
*
* @param processInstance Flowable流程实例
* @param variables 流程变量
* @return 工作流实例
*/
WorkflowInstance createWorkflowInstance(ProcessInstance processInstance, Map<String, Object> variables);
WorkflowInstanceDTO createWorkflowInstance(Long workflowDefinitionId, String businessKey, ProcessInstance processInstance);
/**
* 更新工作流实例状态

View File

@ -1,15 +1,20 @@
package com.qqchen.deploy.backend.workflow.service.impl;
import com.qqchen.deploy.backend.framework.service.impl.BaseServiceImpl;
import com.qqchen.deploy.backend.workflow.converter.WorkflowInstanceConverter;
import com.qqchen.deploy.backend.workflow.dto.WorkflowDefinitionDTO;
import com.qqchen.deploy.backend.workflow.dto.WorkflowExecutionDTO;
import com.qqchen.deploy.backend.workflow.dto.WorkflowInstanceCreateDTO;
import com.qqchen.deploy.backend.workflow.dto.WorkflowInstanceDTO;
import com.qqchen.deploy.backend.workflow.dto.graph.WorkflowDefinitionGraph;
import com.qqchen.deploy.backend.workflow.entity.WorkflowDefinition;
import com.qqchen.deploy.backend.workflow.entity.WorkflowInstance;
import com.qqchen.deploy.backend.workflow.enums.WorkflowInstanceStatusEnums;
import com.qqchen.deploy.backend.workflow.enums.WorkflowStatusEnums;
import com.qqchen.deploy.backend.workflow.repository.IWorkflowDefinitionRepository;
import com.qqchen.deploy.backend.workflow.repository.IWorkflowInstanceRepository;
import com.qqchen.deploy.backend.workflow.service.IWorkflowDefinitionService;
import com.qqchen.deploy.backend.workflow.service.IWorkflowInstanceService;
import com.qqchen.deploy.backend.workflow.util.BpmnConverter;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
@ -24,6 +29,7 @@ import org.flowable.engine.history.HistoricActivityInstance;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.runtime.Execution;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.bpmn.model.Process;
@ -31,6 +37,7 @@ import org.flowable.bpmn.model.FlowElement;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@ -38,7 +45,6 @@ import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
/**
* 工作流定义服务实现
*/
@ -64,9 +70,12 @@ public class WorkflowDefinitionServiceImpl extends BaseServiceImpl<WorkflowDefin
@Resource
private IWorkflowDefinitionRepository workflowDefinitionRepository;
@Resource
private BpmnConverter bpmnConverter;
@Resource
private IWorkflowInstanceService workflowInstanceService;
@Override
@Transactional(rollbackFor = Exception.class)
@ -78,14 +87,15 @@ public class WorkflowDefinitionServiceImpl extends BaseServiceImpl<WorkflowDefin
@Override
@Transactional(rollbackFor = Exception.class)
public void deployWorkflow(WorkflowDefinition workflowDefinition) {
public Deployment deployWorkflow(WorkflowDefinition workflowDefinition) {
try {
// 部署流程
repositoryService.createDeployment()
Deployment deployment = repositoryService.createDeployment()
.addString(workflowDefinition.getKey() + ".bpmn20.xml", workflowDefinition.getBpmnXml())
.name(workflowDefinition.getName())
.deploy();
log.info("Successfully deployed workflow: {}", workflowDefinition.getName());
return deployment;
} catch (Exception e) {
log.error("Failed to deploy workflow: {}", workflowDefinition.getName(), e);
throw new RuntimeException("Failed to deploy workflow", e);
@ -93,25 +103,18 @@ public class WorkflowDefinitionServiceImpl extends BaseServiceImpl<WorkflowDefin
}
@Override
@Transactional
public WorkflowInstanceCreateDTO startWorkflow(String processKey, String businessKey, Map<String, Object> variables) {
@Transactional(rollbackFor = Exception.class)
public WorkflowInstanceDTO startWorkflow(String processKey, String businessKey, Map<String, Object> variables) {
try {
// 2. 创建工作流实例记录
WorkflowDefinition workflowDefinition = workflowDefinitionRepository.findByKey(processKey).orElseThrow(() -> new RuntimeException("Workflow definition process key not found: " + processKey));
// 1. 创建并异步启动流程实例
ProcessInstance processInstance = runtimeService.createProcessInstanceBuilder()
.processDefinitionKey(processKey)
.businessKey(businessKey)
.variables(variables)
.startAsync(); // 异步启动会自动执行 shell 任务
// .start();
// 2. 返回实例信息
WorkflowInstanceCreateDTO dto = new WorkflowInstanceCreateDTO();
dto.setProcessInstanceId(processInstance.getId());
dto.setProcessDefinitionKey(processKey);
dto.setBusinessKey(businessKey);
dto.setStatus("RUNNING"); // 因为实例已经在运行了
return dto;
return workflowInstanceService.createWorkflowInstance(workflowDefinition.getId(), businessKey, processInstance);
} catch (Exception e) {
log.error("Failed to create workflow: {}", processKey, e);
throw new RuntimeException("Failed to create workflow", e);
@ -345,9 +348,11 @@ public class WorkflowDefinitionServiceImpl extends BaseServiceImpl<WorkflowDefin
.orElseThrow(() -> new RuntimeException("Workflow definition not found: " + workflowDefinitionId));
WorkflowDefinitionGraph graph = definition.getGraph();
definition.setBpmnXml(bpmnConverter.convertToXml(graph, definition.getKey()));
Deployment deployment = this.deployWorkflow(definition);
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().deploymentId(deployment.getId()).singleResult();
definition.setStatus(WorkflowStatusEnums.PUBLISHED);
this.deployWorkflow(definition);
definition.setFlowVersion(1);
definition.setProcessDefinitionId(processDefinition.getId());
workflowDefinitionRepository.save(definition);
log.info("Successfully published workflow definition: {}", workflowDefinitionId);
}

View File

@ -2,11 +2,13 @@ package com.qqchen.deploy.backend.workflow.service.impl;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.qqchen.deploy.backend.workflow.converter.WorkflowInstanceConverter;
import com.qqchen.deploy.backend.workflow.dto.WorkflowInstanceDTO;
import com.qqchen.deploy.backend.workflow.entity.WorkflowInstance;
import com.qqchen.deploy.backend.workflow.enums.WorkflowInstanceStatusEnums;
import com.qqchen.deploy.backend.workflow.repository.WorkflowInstanceRepository;
import com.qqchen.deploy.backend.workflow.repository.IWorkflowInstanceRepository;
import com.qqchen.deploy.backend.workflow.service.IWorkflowInstanceService;
import jakarta.annotation.Resource;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.HistoryService;
@ -24,135 +26,137 @@ import java.util.stream.Collectors;
@Service
@RequiredArgsConstructor
public class WorkflowInstanceServiceImpl implements IWorkflowInstanceService {
private final WorkflowInstanceRepository workflowInstanceRepository;
private final IWorkflowInstanceRepository workflowInstanceRepository;
private final RuntimeService runtimeService;
private final HistoryService historyService;
private final ObjectMapper objectMapper;
@Resource
private WorkflowInstanceConverter workflowInstanceConverter;
@Override
@Transactional
public WorkflowInstance createWorkflowInstance(ProcessInstance processInstance, Map<String, Object> variables) {
WorkflowInstance instance = new WorkflowInstance();
instance.setProcessInstanceId(processInstance.getId());
instance.setProcessDefinitionId(Long.valueOf(processInstance.getProcessDefinitionId().split(":")[0]));
instance.setBusinessKey(processInstance.getBusinessKey());
instance.setStatus(WorkflowInstanceStatusEnums.RUNNING);
instance.setStartTime(LocalDateTime.now());
try {
instance.setVariables(objectMapper.writeValueAsString(variables));
} catch (JsonProcessingException e) {
log.error("Failed to serialize variables", e);
instance.setVariables("{}");
}
return workflowInstanceRepository.save(instance);
public WorkflowInstanceDTO createWorkflowInstance(Long workflowDefinitionId, String businessKey, ProcessInstance processInstance) {
WorkflowInstance workflowInstance = new WorkflowInstance();
workflowInstance.setProcessInstanceId(processInstance.getId());
workflowInstance.setProcessDefinitionId(processInstance.getProcessDefinitionId());
workflowInstance.setWorkflowDefinitionId(workflowDefinitionId);
workflowInstance.setBusinessKey(businessKey);
workflowInstance.setStatus(WorkflowInstanceStatusEnums.CREATED);
workflowInstance.setStartTime(LocalDateTime.now());
workflowInstanceRepository.save(workflowInstance);
// 3. 返回创建结果
return workflowInstanceConverter.toDto(workflowInstance);
}
@Override
@Transactional
public WorkflowInstance updateInstanceStatus(String processInstanceId, WorkflowInstanceStatusEnums status) {
WorkflowInstance instance = workflowInstanceRepository.findByProcessInstanceId(processInstanceId)
.orElseThrow(() -> new RuntimeException("Workflow instance not found: " + processInstanceId));
.orElseThrow(() -> new RuntimeException("Workflow instance not found: " + processInstanceId));
instance.setStatus(status);
if (status == WorkflowInstanceStatusEnums.COMPLETED || status == WorkflowInstanceStatusEnums.FAILED) {
instance.setEndTime(LocalDateTime.now());
}
return workflowInstanceRepository.save(instance);
}
@Override
public WorkflowInstanceDTO getInstanceDetails(String processInstanceId) {
WorkflowInstance instance = workflowInstanceRepository.findByProcessInstanceId(processInstanceId)
.orElseThrow(() -> new RuntimeException("Workflow instance not found: " + processInstanceId));
WorkflowInstanceDTO dto = new WorkflowInstanceDTO();
// dto.setId(instance.getProcessInstanceId());
dto.setProcessDefinitionId(String.valueOf(instance.getProcessDefinitionId()));
dto.setBusinessKey(instance.getBusinessKey());
dto.setStatus(instance.getStatus());
// Convert LocalDateTime to Date
dto.setStartTime(java.sql.Timestamp.valueOf(instance.getStartTime()));
if (instance.getEndTime() != null) {
dto.setEndTime(java.sql.Timestamp.valueOf(instance.getEndTime()));
}
// Calculate duration if both start and end time exist
if (instance.getStartTime() != null && instance.getEndTime() != null) {
dto.setDurationInMillis(java.time.Duration.between(instance.getStartTime(), instance.getEndTime()).toMillis());
}
// Get variables
try {
@SuppressWarnings("unchecked")
Map<String, Object> variables = objectMapper.readValue(instance.getVariables(), Map.class);
dto.setVariables(variables);
} catch (JsonProcessingException e) {
log.error("Failed to deserialize variables", e);
dto.setVariables(new HashMap<>());
}
// Get activity instances
List<HistoricActivityInstance> activities = historyService.createHistoricActivityInstanceQuery()
.processInstanceId(processInstanceId)
.orderByHistoricActivityInstanceStartTime().asc()
.list();
dto.setActivities(activities.stream().map(this::convertToActivityInstance).collect(Collectors.toList()));
return dto;
.orElseThrow(() -> new RuntimeException("Workflow instance not found: " + processInstanceId));
// WorkflowInstanceDTO dto = new WorkflowInstanceDTO();
//// dto.setId(instance.getProcessInstanceId());
// dto.setProcessDefinitionId(String.valueOf(instance.getProcessDefinitionId()));
// dto.setBusinessKey(instance.getBusinessKey());
// dto.setStatus(instance.getStatus());
//
// // Convert LocalDateTime to Date
// dto.setStartTime(java.sql.Timestamp.valueOf(instance.getStartTime()));
// if (instance.getEndTime() != null) {
// dto.setEndTime(java.sql.Timestamp.valueOf(instance.getEndTime()));
// }
//
// // Calculate duration if both start and end time exist
// if (instance.getStartTime() != null && instance.getEndTime() != null) {
// dto.setDurationInMillis(java.time.Duration.between(instance.getStartTime(), instance.getEndTime()).toMillis());
// }
//
// // Get variables
// try {
// @SuppressWarnings("unchecked")
// Map<String, Object> variables = objectMapper.readValue(instance.getVariables(), Map.class);
// dto.setVariables(variables);
// } catch (JsonProcessingException e) {
// log.error("Failed to deserialize variables", e);
// dto.setVariables(new HashMap<>());
// }
//
// // Get activity instances
// List<HistoricActivityInstance> activities = historyService.createHistoricActivityInstanceQuery()
// .processInstanceId(processInstanceId)
// .orderByHistoricActivityInstanceStartTime().asc()
// .list();
//
// dto.setActivities(activities.stream().map(this::convertToActivityInstance).collect(Collectors.toList()));
// return dto;
return null;
}
@Override
public List<WorkflowInstanceDTO> findByBusinessKey(String businessKey) {
return workflowInstanceRepository.findByBusinessKey(businessKey).stream()
.map(instance -> getInstanceDetails(instance.getProcessInstanceId()))
.collect(Collectors.toList());
.map(instance -> getInstanceDetails(instance.getProcessInstanceId()))
.collect(Collectors.toList());
}
@Override
@Transactional
public void completeInstance(String processInstanceId, Map<String, Object> variables) {
// Update Flowable variables
runtimeService.setVariables(processInstanceId, variables);
// Update our instance
WorkflowInstance instance = workflowInstanceRepository.findByProcessInstanceId(processInstanceId)
.orElseThrow(() -> new RuntimeException("Workflow instance not found: " + processInstanceId));
.orElseThrow(() -> new RuntimeException("Workflow instance not found: " + processInstanceId));
try {
instance.setVariables(objectMapper.writeValueAsString(variables));
} catch (JsonProcessingException e) {
log.error("Failed to serialize variables", e);
}
instance.setStatus(WorkflowInstanceStatusEnums.COMPLETED);
instance.setEndTime(LocalDateTime.now());
workflowInstanceRepository.save(instance);
}
private WorkflowInstanceDTO.ActivityInstance convertToActivityInstance(HistoricActivityInstance hai) {
WorkflowInstanceDTO.ActivityInstance ai = new WorkflowInstanceDTO.ActivityInstance();
ai.setId(hai.getId());
ai.setActivityId(hai.getActivityId());
ai.setActivityName(hai.getActivityName());
ai.setActivityType(hai.getActivityType());
ai.setStartTime(hai.getStartTime());
ai.setEndTime(hai.getEndTime());
ai.setDurationInMillis(hai.getDurationInMillis());
// Get shell task execution details from variables if available
if ("serviceTask".equals(hai.getActivityType())) {
Map<String, Object> variables = runtimeService.getVariables(hai.getExecutionId());
ai.setShellOutput((String) variables.get("shellOutput"));
ai.setShellError((String) variables.get("shellError"));
ai.setShellExitCode((Integer) variables.get("shellExitCode"));
}
return ai;
}
// private WorkflowInstanceDTO.ActivityInstance convertToActivityInstance(HistoricActivityInstance hai) {
// WorkflowInstanceDTO.ActivityInstance ai = new WorkflowInstanceDTO.ActivityInstance();
// ai.setId(hai.getId());
// ai.setActivityId(hai.getActivityId());
// ai.setActivityName(hai.getActivityName());
// ai.setActivityType(hai.getActivityType());
// ai.setStartTime(hai.getStartTime());
// ai.setEndTime(hai.getEndTime());
// ai.setDurationInMillis(hai.getDurationInMillis());
//
// // Get shell task execution details from variables if available
// if ("serviceTask".equals(hai.getActivityType())) {
// Map<String, Object> variables = runtimeService.getVariables(hai.getExecutionId());
// ai.setShellOutput((String) variables.get("shellOutput"));
// ai.setShellError((String) variables.get("shellError"));
// ai.setShellExitCode((Integer) variables.get("shellExitCode"));
// }
//
// return ai;
// }
}

View File

@ -1,229 +0,0 @@
//package com.qqchen.deploy.backend.workflow.util;
//
//import com.fasterxml.jackson.databind.ObjectMapper;
//import com.qqchen.deploy.backend.workflow.dto.graph.*;
//import com.qqchen.deploy.backend.workflow.enums.NodeTypeEnums;
//import lombok.Data;
//import lombok.extern.slf4j.Slf4j;
//
//import java.util.ArrayList;
//import java.util.HashMap;
//import java.util.List;
//import java.util.Map;
//
///**
// * 工作流定义图形生成工具类
// * 用于生成示例工作流定义包括
// * 1. 简单工作流开始 -> 脚本任务 -> 结束
// * 2. 复杂工作流开始 -> 脚本任务A -> 脚本任务B -> 结束
// */
//@Data
//@Slf4j
//public class WorkflowDefinitionGraph {
// private static final ObjectMapper mapper = new ObjectMapper();
//
// /**
// * 节点列表
// */
// private List<WorkflowDefinitionNode> nodes;
//
// /**
// * 边列表
// */
// private List<WorkflowDefinitionEdge> edges;
//
// /**
// * 生成简单工作流
// * 开始 -> 脚本任务 -> 结束
// */
// public static WorkflowDefinitionGraph generateSimpleWorkflow() {
// WorkflowDefinitionGraph graph = new WorkflowDefinitionGraph();
// List<WorkflowDefinitionNode> nodes = new ArrayList<>();
// List<WorkflowDefinitionEdge> edges = new ArrayList<>();
//
// // 开始节点
// WorkflowDefinitionNode startNode = createNode(
// "startEvent1",
// NodeTypeEnums.START_EVENT,
// "开始",
// 100, 100,
// createNodeConfig("开始节点", "启动流程")
// );
// nodes.add(startNode);
//
// // 脚本任务节点
// Map<String, Object> scriptConfig = createNodeConfig("脚本任务", "执行一个简单的Shell脚本");
// scriptConfig.put("script", "echo 'Hello World'");
// scriptConfig.put("language", "shell");
//
// WorkflowDefinitionNode scriptNode = createNode(
// "scriptTask1",
// NodeTypeEnums.SCRIPT_TASK,
// "执行脚本",
// 300, 100,
// scriptConfig
// );
// nodes.add(scriptNode);
//
// // 结束节点
// WorkflowDefinitionNode endNode = createNode(
// "endEvent1",
// NodeTypeEnums.END_EVENT,
// "结束",
// 500, 100,
// createNodeConfig("结束节点", "流程结束")
// );
// nodes.add(endNode);
//
// // 添加连线
// edges.add(createEdge("flow1", "startEvent1", "scriptTask1", "开始到脚本"));
// edges.add(createEdge("flow2", "scriptTask1", "endEvent1", "脚本到结束"));
//
// graph.setNodes(nodes);
// graph.setEdges(edges);
// return graph;
// }
//
// /**
// * 生成复杂工作流
// * 开始 -> 脚本任务A -> 脚本任务B -> 结束
// */
// public static WorkflowDefinitionGraph generateComplexWorkflow() {
// WorkflowDefinitionGraph graph = new WorkflowDefinitionGraph();
// List<WorkflowDefinitionNode> nodes = new ArrayList<>();
// List<WorkflowDefinitionEdge> edges = new ArrayList<>();
//
// // 开始节点
// WorkflowDefinitionNode startNode = createNode(
// "startEvent1",
// NodeTypeEnums.START_EVENT,
// "开始",
// 100, 100,
// createNodeConfig("开始节点", "启动流程")
// );
// nodes.add(startNode);
//
// // 脚本任务A
// Map<String, Object> scriptConfigA = createNodeConfig("脚本任务A", "数据处理");
// scriptConfigA.put("script", "process_data.sh");
// scriptConfigA.put("language", "shell");
//
// WorkflowDefinitionNode scriptNodeA = createNode(
// "scriptTask1",
// NodeTypeEnums.SCRIPT_TASK,
// "数据处理",
// 300, 100,
// scriptConfigA
// );
// nodes.add(scriptNodeA);
//
// // 脚本任务B
// Map<String, Object> scriptConfigB = createNodeConfig("脚本任务B", "生成报告");
// scriptConfigB.put("script", "generate_report.sh");
// scriptConfigB.put("language", "shell");
//
// WorkflowDefinitionNode scriptNodeB = createNode(
// "scriptTask2",
// NodeTypeEnums.SCRIPT_TASK,
// "生成报告",
// 500, 100,
// scriptConfigB
// );
// nodes.add(scriptNodeB);
//
// // 结束节点
// WorkflowDefinitionNode endNode = createNode(
// "endEvent1",
// NodeTypeEnums.END_EVENT,
// "结束",
// 700, 100,
// createNodeConfig("结束节点", "流程结束")
// );
// nodes.add(endNode);
//
// // 添加连线
// edges.add(createEdge("flow1", "startEvent1", "scriptTask1", "开始到处理"));
// edges.add(createEdge("flow2", "scriptTask1", "scriptTask2", "处理到报告"));
// edges.add(createEdge("flow3", "scriptTask2", "endEvent1", "报告到结束"));
//
// graph.setNodes(nodes);
// graph.setEdges(edges);
// return graph;
// }
//
// /**
// * 创建节点
// */
// private static WorkflowDefinitionNode createNode(String id, NodeTypeEnums type, String name, int x, int y, Map<String, Object> config) {
// WorkflowDefinitionNode node = new WorkflowDefinitionNode();
// node.setId(id);
// node.setCode(type.getCode());
// node.setType(type);
// node.setName(name);
// node.setConfig(config);
//
// // 从枚举的uiConfig中获取配置并创建新的图形配置
// WorkflowNodeGraph originalConfig = type.getUiConfig();
// WorkflowNodeGraph nodeGraph = new WorkflowNodeGraph()
// .setShape(originalConfig.getShape())
// .setSize(originalConfig.getSize().getWidth(), originalConfig.getSize().getHeight())
// .setStyle(originalConfig.getStyle().getFill(),
// originalConfig.getStyle().getStroke(),
// originalConfig.getStyle().getIcon())
// .configPorts(originalConfig.getPorts().getTypes())
// .setPosition(x, y);
//
// node.setGraph(nodeGraph);
// return node;
// }
//
// /**
// * 创建节点配置
// */
// private static Map<String, Object> createNodeConfig(String name, String description) {
// Map<String, Object> config = new HashMap<>();
// config.put("name", name);
// config.put("description", description);
// return config;
// }
//
// /**
// * 创建连线
// */
// private static WorkflowDefinitionEdge createEdge(String id, String from, String to, String name) {
// return createEdge(id, from, to, name, null);
// }
//
// /**
// * 创建带条件的连线
// */
// private static WorkflowDefinitionEdge createEdge(String id, String from, String to, String name, String condition) {
// WorkflowDefinitionEdge edge = new WorkflowDefinitionEdge();
// edge.setId(id);
// edge.setFrom(from);
// edge.setTo(to);
// edge.setName(name);
//
// // 设置边配置
// WorkflowDefinitionEdgeConfig config = new WorkflowDefinitionEdgeConfig();
// config.setType("sequence");
// if (condition != null) {
// config.setCondition(condition);
// config.setConditionExpression(condition);
// }
// edge.setConfig(config);
//
// return edge;
// }
//
// public static void main(String[] args) {
// try {
// System.out.println("=== 简单工作流 ===");
// System.out.println(mapper.writerWithDefaultPrettyPrinter().writeValueAsString(generateSimpleWorkflow()));
// System.out.println("\n=== 复杂工作流 ===");
// System.out.println(mapper.writerWithDefaultPrettyPrinter().writeValueAsString(generateComplexWorkflow()));
// } catch (Exception e) {
// log.error("生成工作流定义失败", e);
// }
// }
//}

View File

@ -158,7 +158,7 @@ INSERT INTO sys_external_system (
-- 工作流定义测试数据
INSERT INTO workflow_definition (
-- 基础信息
name, `key`, flow_version, description, category,
name, `key`, process_definition_id, flow_version, description, category,
-- 流程配置
graph, form_config, tags,
-- 流程属性
@ -168,7 +168,7 @@ INSERT INTO workflow_definition (
) VALUES
-- 简单脚本流程:开始 -> 脚本任务 -> 结束
(
'简单脚本流程', 'simple_script_flow', 1, '一个包含脚本任务的简单流程', 'test',
'简单脚本流程', 'simple_script_flow', null, 1, '一个包含脚本任务的简单流程', 'test',
'{
"nodes" : [ {
"id" : "startEvent1",
@ -337,7 +337,7 @@ INSERT INTO workflow_definition (
-- 复杂业务流程:开始 -> 脚本任务A -> 脚本任务B -> 结束
(
'复杂业务流程', 'complex_business_flow', 1, '包含多个脚本任务节点的业务流程', 'business',
'复杂业务流程', 'complex_business_flow', null, 1, '包含多个脚本任务节点的业务流程', 'business',
'{
"nodes" : [ {
"id" : "startEvent1",