diff --git a/pigx-flow/pigx-flow-api/src/main/java/com/pig4cloud/pigx/flow/dto/ProcessInstanceParamDto.java b/pigx-flow/pigx-flow-api/src/main/java/com/pig4cloud/pigx/flow/dto/ProcessInstanceParamDto.java new file mode 100644 index 000000000..6f4797751 --- /dev/null +++ b/pigx-flow/pigx-flow-api/src/main/java/com/pig4cloud/pigx/flow/dto/ProcessInstanceParamDto.java @@ -0,0 +1,58 @@ +package com.pig4cloud.pigx.flow.dto; + +import lombok.Data; + +import java.util.HashMap; +import java.util.Map; + +/** + * 流程实例参数数据传输对象 + *
+ * 该DTO用于启动流程实例或操作流程实例时传递参数。 包含流程定义信息、流程变量、发起人等核心信息。 主要用于流程引擎的实例创建和流程变量设置。 + *
+ * + * @author pigx + */ +@Data +public class ProcessInstanceParamDto { + + /** + * 流程定义ID + *+ * 要启动的流程定义的唯一标识。 对应已部署的流程模板ID,如:leave_process_v1。 + *
+ */ + private String flowId; + + /** + * 流程变量集合 + *+ * 存储流程执行过程中需要的各种变量,如: - 表单数据:申请金额、请假天数等 - 控制变量:审批级别、分支条件等 - 业务数据:关联的业务ID、业务类型等 + * 这些变量会在流程执行过程中被各个节点使用。 + *
+ */ + private Map+ * 发起流程实例的用户ID。 用于记录流程的发起者,也可能作为第一个任务的执行人。 + *
+ */ + private String startUserId; + + /** + * 流程实例ID + *+ * 已存在的流程实例ID,用于对已有流程实例进行操作。 如果是启动新流程,此字段为空; 如果是操作已有流程(如设置变量),则需要提供此ID。 + *
+ */ + private String processInstanceId; + + /** 状态 */ + private Integer status; + + /** 完成原因 */ + private String finishReason; + +} diff --git a/pigx-flow/pigx-flow-api/src/main/java/com/pig4cloud/pigx/flow/dto/ProcessNodeRecordParamDto.java b/pigx-flow/pigx-flow-api/src/main/java/com/pig4cloud/pigx/flow/dto/ProcessNodeRecordParamDto.java new file mode 100644 index 000000000..2f196438a --- /dev/null +++ b/pigx-flow/pigx-flow-api/src/main/java/com/pig4cloud/pigx/flow/dto/ProcessNodeRecordParamDto.java @@ -0,0 +1,103 @@ +package com.pig4cloud.pigx.flow.dto; + +import lombok.Data; + +/** + * 流程节点记录参数数据传输对象 + *+ * 该DTO用于创建流程节点的执行记录。记录节点的执行信息, 包括节点类型、表单数据、执行上下文等。 主要用于流程历史记录的创建和流程轨迹的追踪。 + *
+ * + * @author pigx + */ +@Data +public class ProcessNodeRecordParamDto { + + /** + * 流程定义ID + *+ * 流程模板的唯一标识。 标识该记录所属的流程定义。 + *
+ */ + private String flowId; + + /** + * 流程实例ID + *+ * 运行中的流程实例唯一标识。 用于关联到具体的流程实例。 + *
+ */ + private String processInstanceId; + + /** + * 表单数据 + *+ * JSON格式的表单数据,包含节点执行时的业务数据。 记录节点处理时的表单内容快照。 + *
+ */ + private String data; + + /** + * 节点ID + *+ * 流程节点的唯一标识。 标识具体执行的是哪个节点。 + *
+ */ + private String nodeId; + + /** + * 节点类型 + *+ * 节点的类型标识,对应NodeTypeEnum: - ROOT: 发起人节点 - APPROVAL: 审批节点 - CC: 抄送节点 - CONDITION: 条件节点 + * - CONCURRENT: 并行节点 - DELAY: 延迟节点 - TRIGGER: 触发器节点 - EMPTY: 空节点 - END: 结束节点 + *
+ */ + private String nodeType; + + /** + * 节点名称 + *+ * 流程节点的显示名称,如"部门经理审批"、"财务审核"等。 用于在界面上展示,便于用户理解。 + *
+ */ + private String nodeName; + + /** + * 执行ID + *+ * Flowable引擎的执行ID。 用于关联流程引擎中的执行实例。 + *
+ */ + private String executionId; + + /** + * 任务ID + *+ * Flowable引擎生成的任务ID。 对于用户任务节点,记录对应的任务ID。 + *
+ */ + private String taskId; + + /** + * 审批意见 + *+ * 节点执行时的意见或备注。 通常用于审批节点记录审批意见。 + *
+ */ + private String approveDesc; + + /** + * 任务类型 + *+ * 标识任务的具体类型,用于区分不同的处理逻辑: - APPROVAL: 审批任务 - COPY: 抄送任务 - NOTIFY: 通知任务 - SYSTEM: 系统任务 + *
+ */ + private String taskType; + + /** 状态 */ + private Integer status; + + /** 完成原因 */ + private String finishReason; + +} diff --git a/pigx-flow/pigx-flow-api/src/main/java/com/pig4cloud/pigx/flow/entity/Process.java b/pigx-flow/pigx-flow-api/src/main/java/com/pig4cloud/pigx/flow/entity/Process.java new file mode 100644 index 000000000..b841172db --- /dev/null +++ b/pigx-flow/pigx-flow-api/src/main/java/com/pig4cloud/pigx/flow/entity/Process.java @@ -0,0 +1,146 @@ +package com.pig4cloud.pigx.flow.entity; + +import com.baomidou.mybatisplus.annotation.*; +import com.pig4cloud.pigx.common.core.util.TenantTable; +import lombok.Getter; +import lombok.Setter; +import lombok.experimental.Accessors; + +import java.time.LocalDateTime; + +/** + * 流程定义实体类 + *+ * 该实体类用于存储工作流程的定义信息,包括流程的基本信息、表单配置、流程配置等。 每个流程定义可以创建多个流程实例,支持多租户隔离。 + *
+ * + * @author Vincent + * @since 2023-07-06 + */ +@Getter +@Setter +@TenantTable +@Accessors(chain = true) +@TableName("process") +public class Process { + + /** + * 流程唯一标识ID 用于唯一标识一个流程定义,在流程实例创建时使用 + */ + @TableField("flow_id") + private String flowId; + + /** + * 流程名称 流程的显示名称,用于在流程列表中展示 + */ + @TableField("name") + private String name; + + /** + * 流程图标配置 存储流程的图标信息,支持自定义图标样式 + */ + @TableField("logo") + private String logo; + + /** + * 流程设置项 JSON格式存储流程的各种配置信息,如通知设置、权限设置等 + */ + @TableField("settings") + private String settings; + + /** + * 流程分组ID 关联process_group表,用于对流程进行分类管理 + */ + @TableField("group_id") + private Long groupId; + + /** 表单配置 */ + @TableField("form_config") + private String formConfig; + + /** + * 表单配置内容 JSON格式存储表单的结构定义,包括表单项类型、验证规则、默认值等 + */ + @TableField("form_items") + private String formItems; + + /** + * 流程配置内容 JSON格式存储流程的节点信息、流转条件、审批规则等核心流程定义 + */ + @TableField("process") + private String process; + + /** + * 流程备注说明 用于记录流程的用途、注意事项等补充信息 + */ + @TableField("remark") + private String remark; + + /** + * 排序号 用于控制流程在列表中的显示顺序,数值越小越靠前 + */ + @TableField("sort") + private Integer sort; + + /** + * 流程隐藏标识 0=正常显示,1=隐藏(隐藏的流程不在列表中显示,但仍可使用) + */ + @TableField("is_hidden") + private String hidden; + + /** + * 流程停用标识 0=正常启用,1=停用(停用的流程不能创建新实例) + */ + @TableField("is_stop") + private String stop; + + /** + * 流程管理员ID 主管理员用户ID,拥有该流程的完全管理权限 + */ + @TableField("admin_id") + private Long adminId; + + /** + * 流程全局唯一ID 用于流程的版本控制和跨系统识别 + */ + @TableField("unique_id") + private String uniqueId; + + /** + * 管理员列表 JSON格式存储多个管理员ID,支持多人共同管理流程 + */ + @TableField("admin_list") + private String adminList; + + /** + * 流程使用范围描述 显示该流程的适用部门、人员范围等信息 + */ + @TableField("range_show") + private String rangeShow; + + /** + * 主键ID 使用雪花算法生成的分布式ID + */ + @TableId(value = "id", type = IdType.ASSIGN_ID) + private Long id; + + /** + * 逻辑删除字段 + */ + @TableLogic + @TableField(fill = FieldFill.INSERT) + private String delFlag; + + /** + * 创建时间 + */ + @TableField(fill = FieldFill.INSERT) + private LocalDateTime createTime; + + /** + * 更新时间 + */ + @TableField(fill = FieldFill.INSERT_UPDATE) + private LocalDateTime updateTime; + +} diff --git a/pigx-flow/pigx-flow-biz/src/main/java/com/pig4cloud/pigx/flow/controller/ProcessFlowController.java b/pigx-flow/pigx-flow-biz/src/main/java/com/pig4cloud/pigx/flow/controller/ProcessFlowController.java new file mode 100644 index 000000000..913a58dce --- /dev/null +++ b/pigx-flow/pigx-flow-biz/src/main/java/com/pig4cloud/pigx/flow/controller/ProcessFlowController.java @@ -0,0 +1,238 @@ +package com.pig4cloud.pigx.flow.controller; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.pig4cloud.pigx.common.core.util.R; +import com.pig4cloud.pigx.common.data.tenant.TenantContextHolder; +import com.pig4cloud.pigx.flow.dto.ProcessInstanceParamDto; +import com.pig4cloud.pigx.flow.dto.TaskDto; +import com.pig4cloud.pigx.flow.dto.TaskQueryParamDto; +import com.pig4cloud.pigx.flow.support.utils.NodeUtil; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.flowable.common.engine.impl.identity.Authentication; +import org.flowable.engine.HistoryService; +import org.flowable.engine.RepositoryService; +import org.flowable.engine.RuntimeService; +import org.flowable.engine.TaskService; +import org.flowable.engine.history.HistoricActivityInstance; +import org.flowable.engine.history.HistoricActivityInstanceQuery; +import org.flowable.engine.runtime.ProcessInstance; +import org.flowable.task.api.TaskQuery; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.util.*; + +/** + * 流程引擎核心控制器 + *+ * 该控制器是工作流引擎的核心接口,直接与Flowable引擎交互,提供流程生命周期管理功能: 1. 流程定义的创建和部署 - 将前端设计的流程模型转换为BPMN格式并部署到引擎 + * 2. 流程实例的启动和管理 - 启动流程实例、停止运行中的流程 3. 任务的查询和处理 - 查询待办任务、已办任务,执行任务审批 + *
+ *+ * 该控制器主要供内部系统调用,通过封装Flowable原生API,简化流程操作。 所有操作都支持多租户隔离,确保数据安全。 + *
+ * + */ +@Slf4j +@RestController +@RequiredArgsConstructor +@RequestMapping("/flow") +public class ProcessFlowController { + + private final TaskService taskService; + + private final HistoryService historyService; + + private final RepositoryService repositoryService; + + private final RuntimeService runtimeService; + + /** + * 启动流程实例 + *+ * 根据流程定义ID启动一个新的流程实例。启动时可以传入流程变量, 这些变量会在整个流程执行过程中使用(如条件判断、人员分配等)。 + *
+ * @param processInstanceParamDto 启动参数,包含: - flowId: 流程定义ID - startUserId: 发起人用户ID - + * paramMap: 流程变量Map,用于流程执行中的条件判断和数据传递 + * @return R 统一响应对象,包含启动成功的流程实例ID + */ + @PostMapping("/start") + public R start(@RequestBody ProcessInstanceParamDto processInstanceParamDto) { + Authentication.setAuthenticatedUserId(processInstanceParamDto.getStartUserId()); + ProcessInstance processInstance = runtimeService.startProcessInstanceByKeyAndTenantId( + processInstanceParamDto.getFlowId(), processInstanceParamDto.getParamMap(), + TenantContextHolder.getTenantId().toString()); + + String processInstanceId = processInstance.getProcessInstanceId(); + return R.ok(processInstanceId); + + } + + /** + * 审批任务(测试接口) + *+ * 该接口用于测试流程审批功能,完成指定的任务并设置审批结果。 实际业务中应使用TaskController中更完善的审批接口。 + *
+ * @param taskId 待审批的任务ID + * @param approved 审批结果:true-通过,false-拒绝 + */ + @PostMapping("/approve") + public void approve(String taskId, boolean approved) { + Map+ * 查询指定用户已经完成的历史任务,支持按时间范围过滤。 返回的任务信息包含任务处理时长、完成时间等历史数据。 + *
+ * @param taskQueryParamDto 查询参数,包含: - assign: 任务处理人ID - taskTime: 任务时间范围数组 [开始时间, + * 结束时间] - current: 当前页码 - size: 每页大小 + * @return R 统一响应对象,包含分页的已办任务列表(TaskDto) + */ + @PostMapping("/queryCompletedTask") + public R queryCompletedTask(@RequestBody TaskQueryParamDto taskQueryParamDto) { + HistoricActivityInstanceQuery historicActivityInstanceQuery = historyService + .createHistoricActivityInstanceQuery(); + HistoricActivityInstanceQuery activityInstanceQuery = historicActivityInstanceQuery + .taskAssignee(taskQueryParamDto.getAssign()) + .finished() + .orderByHistoricActivityInstanceEndTime() + .desc(); + + if (ArrayUtil.isNotEmpty(taskQueryParamDto.getTaskTime())) { + ZoneId zoneId = ZoneId.systemDefault(); + ZonedDateTime zonedBeforeDateTime = taskQueryParamDto.getTaskTime()[0].atZone(zoneId); + ZonedDateTime zonedAfterDateTime = taskQueryParamDto.getTaskTime()[1].atZone(zoneId); + Date beforeDate = Date.from(zonedBeforeDateTime.toInstant()); + Date afterDate = Date.from(zonedAfterDateTime.toInstant()); + activityInstanceQuery.finishedBefore(afterDate).finishedAfter(beforeDate); + } + + List+ * 查询分配给指定用户的待处理任务,支持按流程名称和创建时间范围过滤。 待办任务是需要用户处理的活动任务,处理后任务将流转到下一节点。 + *
+ * @param taskQueryParamDto 查询参数,包含: - assign: 任务处理人ID - processName: 流程名称(可选,用于过滤) - + * taskTime: 任务创建时间范围数组 [开始时间, 结束时间] - current: 当前页码 - size: 每页大小 + * @return R 统一响应对象,包含分页的待办任务列表(TaskDto) + */ + @PostMapping("/queryAssignTask") + public R queryAssignTask(@RequestBody TaskQueryParamDto taskQueryParamDto) { + + String assign = taskQueryParamDto.getAssign(); + + List+ * 该类负责管理流程节点的详细数据,主要功能包括: 1. 保存流程节点的配置数据(审批人、表单权限、条件等) 2. 查询指定节点的详细配置信息 3. + * 为流程执行提供节点配置数据支持 + * + * 节点数据以JSON格式存储,包含节点类型、审批人配置、表单权限等信息 + *
+ * + * @author Vincent + * @since 2023-05-07 + */ +@Service +public class ProcessNodeDataServiceImpl extends ServiceImpl+ * 将流程节点的配置信息保存到数据库。节点数据包括: - 节点类型(审批、抄送、条件等) - 审批人配置 - 表单权限设置 - 条件表达式等 + *
+ * @param processNodeDataDto 流程节点数据DTO,包含flowId、nodeId和data(JSON格式的节点配置) + * @return R 保存结果 + */ + @Override + public R saveNodeData(ProcessNodeDataDto processNodeDataDto) { + ProcessNodeData processNodeData = BeanUtil.copyProperties(processNodeDataDto, ProcessNodeData.class); + baseMapper.delete(Wrappers.+ * 根据流程ID和节点ID查询节点的详细配置信息。 节点数据存储为JSON格式,查询后会自动转换为Node对象 + *
+ * @param flowId 流程ID + * @param nodeId 节点ID + * @return R+ * 实现流程定义的核心业务逻辑,包括流程的创建、编辑、查询、部署等功能。 该类是流程管理的核心实现,负责: - 流程定义的CRUD操作 - 流程表单的动态配置管理 - + * 流程节点的解析和验证 - 与Flowable引擎的交互部署 - 流程权限的管理和控制 + *
+ * + * @author cxygzl + * @since 2023-05-25 + */ +@Slf4j +@Service +@RequiredArgsConstructor +public class ProcessServiceImpl extends ServiceImpl+ * 根据流程ID获取完整的流程配置信息,包括: - 流程基本信息 - 表单配置(自动生成序列号字段的值) - 需要发起人选择执行人的节点列表 - 表单权限配置 + *
+ * @param flowId 流程定义ID + * @return 包含流程详细信息的响应对象 + */ + @Override + public R+ * 内部方法,用于构建流程的视图对象。主要处理: - 解析流程节点结构 - 查找需要发起人选择的节点 - 处理序列号类型的表单字段,自动生成下一个序号 - + * 提取起始节点的表单权限配置 + *
+ * @param flowId 流程定义ID + * @return 流程视图对象,包含所有展示所需的信息 + */ + @SneakyThrows + private ProcessVO getProcessVO(String flowId) { + + Process oaForms = getByFlowId(flowId); + String process = oaForms.getProcess(); + String formItems = oaForms.getFormItems(); + Node startNode = objectMapper.readValue(process, new TypeReference<>() { + }); + + List+ * 通过流程的唯一标识符查询流程定义实体。 注意:一个流程可能有多个版本,此方法返回当前有效版本。 + *
+ * @param flowId 流程定义ID + * @return 流程定义实体,如果不存在返回null + */ + @Override + public Process getByFlowId(String flowId) { + return this.lambdaQuery().eq(Process::getFlowId, flowId).one(); + } + + /** + * 根据流程ID更新流程定义 + *+ * 更新流程的配置信息,包括表单、节点、权限等。 更新不会影响已经运行的流程实例。 + *
+ * @param process 包含更新信息的流程实体 + */ + @Override + public void updateByFlowId(Process process) { + this.lambdaUpdate().eq(Process::getFlowId, process.getFlowId()).update(process); + } + + /** + * 隐藏流程定义 + *+ * 将流程标记为隐藏状态,隐藏的流程: - 不在流程列表中显示 - 不能创建新的流程实例 - 已有的流程实例可以继续执行 + *
+ * @param flowId 要隐藏的流程ID + */ + @Override + public void hide(String flowId) { + this.lambdaUpdate() + .set(Process::getHidden, YesNoEnum.YES.getCode()) + .eq(Process::getFlowId, flowId) + .update(new Process()); + } + + /** + * 创建新的流程定义 + *+ * 创建流程的完整流程: 1. 调用流程引擎创建BPMN模型 2. 如果是更新操作,隐藏旧版本 3. 保存流程定义到数据库 4. 设置流程发起人权限 5. + * 生成流程使用范围描述 + *
+ * @param process 流程定义实体,包含流程的所有配置信息 + * @return 创建结果,成功返回流程ID,失败返回错误信息 + */ + @SneakyThrows + @Override + public R create(Process process) { + String flowId; + if (StrUtil.isNotBlank(process.getFlowId())) { + flowId = process.getFlowId(); + } + else { + flowId = "P" + DateUtil.format(new Date(), DatePattern.PURE_DATE_PATTERN) + + RandomUtil.randomString(5).toUpperCase(); + } + + BpmnModel bpmnModel = ModelUtil.buildBpmnModel(objectMapper.readValue(process.getProcess(), Node.class), + process.getName(), flowId); + { + byte[] bpmnBytess = new BpmnXMLConverter().convertToXML(bpmnModel); + String filename = "/tmp/flowable-deployment/" + flowId + ".bpmn20.xml"; + log.debug("部署时的模型文件:{}", filename); + FileUtil.writeBytes(bpmnBytess, filename); + } + + Process oldProcess = this.getByFlowId(flowId); + if (Objects.nonNull(oldProcess) && StrUtil.isNotBlank(oldProcess.getUniqueId())) { + // 挂起原有流程定义 + String oldDeploymentId = oldProcess.getUniqueId(); + + ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery() + .deploymentId(oldDeploymentId) + .singleResult(); + repositoryService.suspendProcessDefinitionById(processDefinition.getId(), true, null); + } + + Deployment deployment = repositoryService.createDeployment() + .addBpmnModel(StrUtil.format("{}.bpmn20.xml", "pig"), bpmnModel) + .tenantId(TenantContextHolder.getTenantId().toString()) + .deploy(); + + NodeUser nodeUser = objectMapper.readValue(process.getAdminList(), new TypeReference+ * 支持三种操作类型: - stop:停用流程(设置stop=1) - delete:删除流程(逻辑删除,设置hidden=1) - 其他:启用流程(设置stop=0) + * 同时支持修改流程所属分组 + *
+ * @param flowId 流程定义ID + * @param type 操作类型:stop(停用)、delete(删除)、其他(启用) + * @param groupId 流程分组ID,可选参数 + * @return 操作结果 + */ + @Override + public R update(String flowId, String type, Long groupId) { + Process process = new Process(); + process.setFlowId(flowId); + process.setStop("stop".equals(type) ? "1" : "0"); + process.setHidden("delete".equals(type) ? "1" : "0"); + process.setGroupId(groupId); + this.updateByFlowId(process); + return R.ok(); + } + +} diff --git a/pigx-flow/pigx-flow-biz/src/main/java/com/pig4cloud/pigx/flow/service/impl/TaskServiceImpl.java b/pigx-flow/pigx-flow-biz/src/main/java/com/pig4cloud/pigx/flow/service/impl/TaskServiceImpl.java new file mode 100644 index 000000000..70b6e43e5 --- /dev/null +++ b/pigx-flow/pigx-flow-biz/src/main/java/com/pig4cloud/pigx/flow/service/impl/TaskServiceImpl.java @@ -0,0 +1,408 @@ +package com.pig4cloud.pigx.flow.service.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.convert.Convert; +import cn.hutool.core.lang.Dict; +import cn.hutool.core.util.StrUtil; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.pig4cloud.pigx.common.core.util.R; +import com.pig4cloud.pigx.common.data.tenant.TenantContextHolder; +import com.pig4cloud.pigx.common.security.util.SecurityUtils; +import com.pig4cloud.pigx.flow.constant.NodeStatusEnum; +import com.pig4cloud.pigx.flow.dto.IndexPageStatistics; +import com.pig4cloud.pigx.flow.dto.Node; +import com.pig4cloud.pigx.flow.dto.TaskParamDto; +import com.pig4cloud.pigx.flow.dto.TaskResultDto; +import com.pig4cloud.pigx.flow.entity.Process; +import com.pig4cloud.pigx.flow.entity.ProcessCopy; +import com.pig4cloud.pigx.flow.entity.ProcessInstanceRecord; +import com.pig4cloud.pigx.flow.entity.ProcessNodeRecordAssignUser; +import com.pig4cloud.pigx.flow.service.*; +import com.pig4cloud.pigx.flow.support.utils.NodeUtil; +import lombok.RequiredArgsConstructor; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.flowable.engine.HistoryService; +import org.flowable.engine.RuntimeService; +import org.flowable.engine.TaskService; +import org.flowable.engine.history.HistoricActivityInstanceQuery; +import org.flowable.engine.runtime.Execution; +import org.flowable.engine.runtime.ProcessInstance; +import org.flowable.task.api.DelegationState; +import org.flowable.task.api.Task; +import org.flowable.task.api.TaskQuery; +import org.flowable.task.api.history.HistoricTaskInstance; +import org.flowable.variable.api.history.HistoricVariableInstance; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; + +/** + * 任务服务实现类 + *+ * 该类是流程任务操作的核心服务,负责处理用户与流程任务的交互,主要功能包括: 1. 任务查询(待办任务详情、任务表单权限等) 2. 任务操作(完成、委托、转办、退回等) 3. + * 任务统计(首页数据看板) 4. 流程控制(终止流程、加签等高级操作) + * + * 该服务整合了流程引擎的任务API,为前端提供统一的任务操作接口 + *
+ * + * @author pigx code generator + * @date 2023-10-01 + */ +@Service +@Slf4j +@RequiredArgsConstructor +public class TaskServiceImpl implements ITaskService { + + private final IProcessService processService; + + private final IProcessCopyService processCopyService; + + private final IProcessNodeDataService nodeDataService; + + private final IProcessNodeRecordAssignUserService processNodeRecordAssignUserService; + + private final IProcessInstanceRecordService processInstanceRecordService; + + private final IFlowableEngineService flowableEngineService; + + private final TaskService taskService; + + private final HistoryService historyService; + + private final RuntimeService runtimeService; + + private final ObjectMapper objectMapper; + + /** + * 查询首页数据看板 + *+ * 获取当前用户的任务统计数据,包括: 1. 待办任务数量 2. 已办任务数量 3. 我发起的流程数量 4. 抄送给我的数量 + *
+ * @return R 包含IndexPageStatistics对象,含有各项统计数据 + */ + @Override + public R queryTaskData() { + + TaskQuery taskQuery = taskService.createTaskQuery(); + + // 待办数量 + long pendingNum = taskQuery.taskAssignee(String.valueOf(SecurityUtils.getUser().getId())) + .taskTenantId(TenantContextHolder.getTenantId().toString()) + .count(); + // 已完成任务 + HistoricActivityInstanceQuery historicActivityInstanceQuery = historyService + .createHistoricActivityInstanceQuery(); + + long completedNum = historicActivityInstanceQuery.taskAssignee(String.valueOf(SecurityUtils.getUser().getId())) + .tenantIdIn(List.of(TenantContextHolder.getTenantId().toString())) + .finished() + .count(); + + IndexPageStatistics indexPageStatistics = IndexPageStatistics.builder() + .pendingNum(pendingNum) + .completedNum(completedNum) + .build(); + + // 获取抄送任务 + Long copyCount = processCopyService.lambdaQuery() + .eq(ProcessCopy::getUserId, SecurityUtils.getUser().getId()) + .count(); + indexPageStatistics.setCopyNum(copyCount); + return R.ok(indexPageStatistics); + } + + /** + * 查询任务 + *+ * 查询指定任务的详细信息,包括: 1. 任务的基本信息(节点名称、执行人等) 2. 流程表单定义和表单数据 3. 当前节点的表单权限配置 4. + * 任务是否可委托、是否是委托任务等状态 + * + * 对于已完成的任务,会从历史记录中获取任务数据 + *
+ * @param taskId 任务ID + * @param view 是否是查看模式(true:只查看,false:可操作) + * @return R 包含任务详情的Dict对象 + * @throws Exception 当解析JSON数据失败时抛出异常 + */ + @SneakyThrows + @Override + public R queryTask(String taskId, boolean view) { + + long userId = SecurityUtils.getUser().getId(); + + Optional+ * 执行任务的完成操作,将任务标记为已完成并流转到下一个节点。 该方法会将当前用户ID设置到任务参数中,确保任务由正确的用户完成 + *
+ * @param taskParamDto 任务参数,包含任务ID、审批意见、流程变量等 + * @return R 操作结果 + */ + @Override + public R completeTask(TaskParamDto taskParamDto) { + long userId = SecurityUtils.getUser().getId(); + taskParamDto.setUserId(String.valueOf(userId)); + + Map+ * 将任务委托给其他用户处理,委托后任务会分配给被委托人, 被委托人完成后任务会返回给原委托人 + *
+ * @param taskParamDto 任务参数,包含任务ID、被委托人ID列表等 + * @return R 操作结果 + */ + @Transactional + @Override + public R delegateTask(TaskParamDto taskParamDto) { + taskParamDto.setUserId(SecurityUtils.getUser().getId().toString()); + return flowableEngineService.delegateTask(taskParamDto); + } + + /** + * 加签完成任务 + *+ * 被委托人完成委托任务后,通过此方法将任务返回给原委托人。 这是委托流程的第二步,用于结束委托状态 + *
+ * @param taskParamDto 任务参数,包含任务ID、审批意见等 + * @return R 操作结果 + */ + @Override + public R resolveTask(TaskParamDto taskParamDto) { + return flowableEngineService.resolveTask(taskParamDto); + } + + /** + * 设置执行人 + *+ * 转办任务给其他用户,与委托不同,转办后任务直接由新执行人处理, 不会返回给原执行人 + *
+ * @param taskParamDto 任务参数,包含任务ID、新执行人ID等 + * @return R 操作结果 + */ + @Override + public R setAssignee(TaskParamDto taskParamDto) { + Map+ * 强制终止流程实例的执行。该方法会: 1. 递归查找并终止所有子流程实例 2. 更新流程实例记录状态为已结束 3. + * 设置结束原因为强制终止(finishReason=9) + * + * 通常用于流程异常或需要强制结束的场景 + *
+ * @param taskParamDto 任务参数,包含流程实例ID + * @return R 操作结果 + */ + @Override + public R stopProcessInstance(TaskParamDto taskParamDto) { + String reqProcessInstanceId = taskParamDto.getProcessInstanceId(); + List+ * 将任务退回到指定的历史节点重新处理。 常用于审批不通过需要重新修改的场景 + *
+ * @param taskParamDto 任务参数,包含任务ID、目标节点ID、退回原因等 + * @return R 操作结果 + */ + @Override + public R back(TaskParamDto taskParamDto) { + taskParamDto.setUserId(SecurityUtils.getUser().getId().toString()); + return flowableEngineService.back(taskParamDto); + } + + /** + * 递归获取所有需要停止的子流程实例ID列表 + *+ * 当一个流程包含子流程时,终止主流程需要同时终止所有子流程。 该方法递归查找指定流程的所有子流程实例ID + *
+ * @param processInstanceId 父流程实例ID + * @return 所有子流程实例ID列表 + */ + private List+ * Flowable全局事件监听器实现,用于监听和处理流程执行过程中的各种事件。 该监听器是流程引擎与业务系统交互的核心组件,负责将流程引擎的事件转换为业务事件。 + *
+ * 监听的主要事件类型: 1. 节点事件:节点开始、节点完成、多实例节点完成 2. 任务事件:任务分配、任务完成 3. 流程事件:流程开始、流程结束 4. + * 变量事件:变量创建、变量更新、变量删除 + *
+ * 主要功能: - 记录流程执行轨迹 - 触发业务系统的相关操作 - 发送任务通知 - 同步流程数据到业务系统 + * + * @author pigx */ @Slf4j public class FlowProcessEventListener implements FlowableEventListener { /** - * 当事件被触发时调用的方法 - * 根据不同事件类型执行不同的业务逻辑 - * - * @param event Flowable引擎触发的事件对象 + * 处理Flowable引擎触发的事件 + *
+ * 该方法是事件监听的核心,根据事件类型分发到不同的处理逻辑。 每种事件类型都会触发相应的业务操作,如记录日志、发送通知等。 + * @param event Flowable引擎触发的事件对象,包含事件类型和相关数据 + * @throws Exception 当事件处理失败时可能抛出异常 */ @SneakyThrows @Override public void onEvent(FlowableEvent event) { - RemoteFlowTaskService remoteFlowTaskService = SpringUtil.getBean(RemoteFlowTaskService.class); + IRemoteService remoteService = SpringUtil.getBean(IRemoteService.class); + IProcessNodeDataService processNodeDataService = SpringUtil.getBean(IProcessNodeDataService.class); log.info("流程事件监听器 类型={} class={}", event.getType(), event.getClass().getCanonicalName()); @@ -65,7 +74,7 @@ public class FlowProcessEventListener implements FlowableEventListener { String flowId = NodeUtil.getFlowId(processDefinitionId); // 查询节点原始数据 - Node node = remoteFlowTaskService.queryNodeOriData(flowId, activityId).getData(); + Node node = processNodeDataService.getNodeData(flowId, activityId).getData(); // 构建节点开始记录参数并发送事件 ProcessNodeRecordParamDto processNodeRecordParamDto = new ProcessNodeRecordParamDto(); @@ -77,13 +86,17 @@ public class FlowProcessEventListener implements FlowableEventListener { } processNodeRecordParamDto.setNodeName(activityName); processNodeRecordParamDto.setExecutionId(flowableActivityEvent.getExecutionId()); - remoteFlowTaskService.startNodeEvent(processNodeRecordParamDto); + remoteService.startNodeEvent(processNodeRecordParamDto); } // 多实例任务完成事件处理 // 触发时机:当多实例任务节点完成时,包括条件完成和全部完成两种情况 - if (event.getType().toString().equals(FlowableEngineEventType.MULTI_INSTANCE_ACTIVITY_COMPLETED_WITH_CONDITION.toString()) - || event.getType().toString().equals(FlowableEngineEventType.MULTI_INSTANCE_ACTIVITY_COMPLETED.toString())) { + if (event.getType() + .toString() + .equals(FlowableEngineEventType.MULTI_INSTANCE_ACTIVITY_COMPLETED_WITH_CONDITION.toString()) + || event.getType() + .toString() + .equals(FlowableEngineEventType.MULTI_INSTANCE_ACTIVITY_COMPLETED.toString())) { FlowableMultiInstanceActivityCompletedEventImpl flowableActivityEvent = (FlowableMultiInstanceActivityCompletedEventImpl) event; String activityId = flowableActivityEvent.getActivityId(); @@ -102,7 +115,8 @@ public class FlowProcessEventListener implements FlowableEventListener { processNodeRecordParamDto.setNodeId(activityId); processNodeRecordParamDto.setNodeName(activityName); - remoteFlowTaskService.endNodeEvent(processNodeRecordParamDto); + remoteService.endNodeEvent(processNodeRecordParamDto); + } // 节点完成事件处理 @@ -125,7 +139,8 @@ public class FlowProcessEventListener implements FlowableEventListener { processNodeRecordParamDto.setNodeId(activityId); processNodeRecordParamDto.setNodeName(activityName); - remoteFlowTaskService.endNodeEvent(processNodeRecordParamDto); + remoteService.endNodeEvent(processNodeRecordParamDto); + } // 变量更新事件处理 @@ -154,7 +169,9 @@ public class FlowProcessEventListener implements FlowableEventListener { // 流程终止事件处理 // 触发时机:当流程以终止结束事件完成时 - if (event.getType().toString().equals(FlowableEngineEventType.PROCESS_COMPLETED_WITH_TERMINATE_END_EVENT.toString())) { + if (event.getType() + .toString() + .equals(FlowableEngineEventType.PROCESS_COMPLETED_WITH_TERMINATE_END_EVENT.toString())) { FlowableProcessTerminatedEventImpl e = (FlowableProcessTerminatedEventImpl) event; DelegateExecution execution = e.getExecution(); String processInstanceId = e.getProcessInstanceId(); @@ -162,11 +179,19 @@ public class FlowProcessEventListener implements FlowableEventListener { log.info("流程终止完成事件 - 流程实例ID: {}", processInstanceId); + String processDefinitionId = execution.getProcessDefinitionId(); + String flowId = NodeUtil.getFlowId(processDefinitionId); // 流程id + // 构建流程结束参数并发送事件 ProcessInstanceParamDto processInstanceParamDto = new ProcessInstanceParamDto(); processInstanceParamDto.setProcessInstanceId(processInstanceId); - processInstanceParamDto.setParamMap(execution.getVariables()); - remoteFlowTaskService.endProcessEvent(processInstanceParamDto); + processInstanceParamDto.setFlowId(flowId); + processInstanceParamDto.setParamMap(execution.getVariables()); + remoteService.endProcess(processInstanceParamDto); + + // 发送任务完成通知 + SpringUtil.getBean(NodeTaskCompleteNotify.class) + .sendFlowNotify(SecurityUtils.getToken(), processInstanceParamDto); } ObjectMapper objectMapper = SpringUtil.getBean(ObjectMapper.class); @@ -180,11 +205,11 @@ public class FlowProcessEventListener implements FlowableEventListener { TaskEntityImpl task = (TaskEntityImpl) flowableEntityEvent.getEntity(); // 获取任务相关信息 - String assignee = task.getAssignee(); // 执行人id - String taskDefinitionKey = task.getTaskDefinitionKey(); // 节点id - String processInstanceId = task.getProcessInstanceId(); // 实例id + String assignee = task.getAssignee(); // 执行人id + String taskDefinitionKey = task.getTaskDefinitionKey(); // 节点id + String processInstanceId = task.getProcessInstanceId(); // 实例id String processDefinitionId = task.getProcessDefinitionId(); - String flowId = NodeUtil.getFlowId(processDefinitionId); // 流程id + String flowId = NodeUtil.getFlowId(processDefinitionId); // 流程id log.info("任务完成事件 - 任务ID: {}, 节点ID: {}, 执行人: {}", task.getId(), taskDefinitionKey, assignee); @@ -193,9 +218,9 @@ public class FlowProcessEventListener implements FlowableEventListener { processNodeRecordAssignUserParamDto.setFlowId(flowId); processNodeRecordAssignUserParamDto.setProcessInstanceId(processInstanceId); processNodeRecordAssignUserParamDto - .setData(objectMapper.writeValueAsString(taskService.getVariables(task.getId()))); + .setData(objectMapper.writeValueAsString(taskService.getVariables(task.getId()))); processNodeRecordAssignUserParamDto - .setLocalData(objectMapper.writeValueAsString(taskService.getVariablesLocal(task.getId()))); + .setLocalData(objectMapper.writeValueAsString(taskService.getVariablesLocal(task.getId()))); processNodeRecordAssignUserParamDto.setNodeId(taskDefinitionKey); processNodeRecordAssignUserParamDto.setUserId(Long.parseLong(task.getAssignee())); processNodeRecordAssignUserParamDto.setTaskId(task.getId()); @@ -204,10 +229,11 @@ public class FlowProcessEventListener implements FlowableEventListener { processNodeRecordAssignUserParamDto.setApproveDesc(Convert.toStr(task.getVariableLocal("approveDesc"))); processNodeRecordAssignUserParamDto.setExecutionId(task.getExecutionId()); - remoteFlowTaskService.taskEndEvent(processNodeRecordAssignUserParamDto); + remoteService.taskEndEvent(processNodeRecordAssignUserParamDto); // 发送任务完成通知 - SpringUtil.getBean(NodeTaskCompleteNotifyService.class).sendNotify(SecurityUtils.getToken(), processNodeRecordAssignUserParamDto); + SpringUtil.getBean(NodeTaskCompleteNotify.class) + .sendNotify(SecurityUtils.getToken(), processNodeRecordAssignUserParamDto); } // 任务分配事件处理 @@ -217,16 +243,16 @@ public class FlowProcessEventListener implements FlowableEventListener { TaskEntityImpl task = (TaskEntityImpl) flowableEntityEvent.getEntity(); // 获取任务分配相关信息 - String assignee = task.getAssignee(); // 执行人id - String owner = task.getOwner(); // 任务拥有者 - String delegationStateString = task.getDelegationStateString(); // 委派状态 - String taskDefinitionKey = task.getTaskDefinitionKey(); // 节点id - String processInstanceId = task.getProcessInstanceId(); // 实例id + String assignee = task.getAssignee(); // 执行人id + String owner = task.getOwner(); // 任务拥有者 + String delegationStateString = task.getDelegationStateString(); // 委派状态 + String taskDefinitionKey = task.getTaskDefinitionKey(); // 节点id + String processInstanceId = task.getProcessInstanceId(); // 实例id String processDefinitionId = task.getProcessDefinitionId(); - String flowId = NodeUtil.getFlowId(processDefinitionId); // 流程id + String flowId = NodeUtil.getFlowId(processDefinitionId); // 流程id - log.info("任务分配事件 - 任务ID: {}, 节点ID: {}, 分配给: {}, 委派状态: {}", - task.getId(), taskDefinitionKey, assignee, delegationStateString); + log.info("任务分配事件 - 任务ID: {}, 节点ID: {}, 分配给: {}, 委派状态: {}", task.getId(), taskDefinitionKey, assignee, + delegationStateString); // 构建任务分配记录参数并发送事件 ProcessNodeRecordAssignUserParamDto processNodeRecordAssignUserParamDto = new ProcessNodeRecordAssignUserParamDto(); @@ -239,14 +265,14 @@ public class FlowProcessEventListener implements FlowableEventListener { // 根据委派状态设置任务类型 processNodeRecordAssignUserParamDto - .setTaskType(StrUtil.equals(DelegationState.PENDING.toString(), delegationStateString) ? "DELEGATION" - : (StrUtil.equals(DelegationState.RESOLVED.toString(), delegationStateString) ? "RESOLVED" - : "")); + .setTaskType(StrUtil.equals(DelegationState.PENDING.toString(), delegationStateString) ? "DELEGATION" + : (StrUtil.equals(DelegationState.RESOLVED.toString(), delegationStateString) ? "RESOLVED" + : "")); processNodeRecordAssignUserParamDto.setApproveDesc(Convert.toStr(task.getVariableLocal("approveDesc"))); processNodeRecordAssignUserParamDto.setExecutionId(task.getExecutionId()); - remoteFlowTaskService.startAssignUser(processNodeRecordAssignUserParamDto); + remoteService.startAssignUser(processNodeRecordAssignUserParamDto); } // 流程开始事件处理 @@ -262,8 +288,8 @@ public class FlowProcessEventListener implements FlowableEventListener { { // 获取流程相关信息 - String nestedProcessInstanceId = flowableProcessStartedEvent.getNestedProcessInstanceId(); // 上级实例id - String flowId = entity.getProcessDefinitionKey(); // 流程定义key + String nestedProcessInstanceId = flowableProcessStartedEvent.getNestedProcessInstanceId(); // 上级实例id + String flowId = entity.getProcessDefinitionKey(); // 流程定义key // 获取启动人信息 Object variable = execution.getVariable("root"); @@ -282,16 +308,16 @@ public class FlowProcessEventListener implements FlowableEventListener { processInstanceRecordParamDto.setFlowId(flowId); processInstanceRecordParamDto.setProcessInstanceId(processInstanceId); processInstanceRecordParamDto.setFormData(objectMapper.writeValueAsString(variables)); - remoteFlowTaskService.createProcessEvent(processInstanceRecordParamDto); + remoteService.createProcessEvent(processInstanceRecordParamDto); } } } /** - * 确定监听器抛出异常是否终止当前操作 - * 返回false表示即使监听器出现异常,流程引擎仍会继续执行 - * - * @return 是否在监听器异常时终止操作 + * 确定监听器抛出异常时是否终止当前操作 + *
+ * 返回false表示即使监听器处理出现异常,流程引擎仍会继续执行。 这确保了监听器的异常不会影响流程的正常执行。 + * @return false,表示监听器异常不终止流程执行 */ @Override public boolean isFailOnException() { @@ -300,9 +326,9 @@ public class FlowProcessEventListener implements FlowableEventListener { /** * 确定监听器是否在事务生命周期事件发生时立即触发 - * 返回false表示不在事务生命周期事件上立即触发 - * - * @return 是否在事务生命周期事件上触发 + *
+ * 返回false表示监听器不需要在事务生命周期事件上立即触发。 这意味着监听器将在正常的事件触发时机执行。 + * @return false,表示不在事务生命周期事件上触发 */ @Override public boolean isFireOnTransactionLifecycleEvent() { @@ -311,12 +337,13 @@ public class FlowProcessEventListener implements FlowableEventListener { /** * 获取在当前事务的生命周期中的触发点 - * 返回null表示不在特定事务生命周期触发点触发 - * - * @return 事务生命周期中的触发点,null表示没有指定 + *
+ * 返回null表示监听器不需要在特定的事务生命周期触发点触发。 可选值包括:committed、committing、rolled-back等。 + * @return null,表示没有指定特定的事务触发点 */ @Override public String getOnTransaction() { return null; } + } \ No newline at end of file diff --git a/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/listeners/NodeTaskCompleteNotify.java b/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/listeners/NodeTaskCompleteNotify.java new file mode 100644 index 000000000..6b7ab81da --- /dev/null +++ b/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/listeners/NodeTaskCompleteNotify.java @@ -0,0 +1,108 @@ +package com.pig4cloud.pigx.flow.support.listeners; + +import cn.hutool.core.lang.Validator; +import cn.hutool.http.HttpRequest; +import cn.hutool.http.HttpResponse; +import cn.hutool.json.JSONUtil; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.pig4cloud.pigx.common.core.util.RetOps; +import com.pig4cloud.pigx.common.security.util.NonWebTokenContextHolder; +import com.pig4cloud.pigx.flow.dto.ProcessInstanceParamDto; +import com.pig4cloud.pigx.flow.dto.ProcessNodeRecordAssignUserParamDto; +import com.pig4cloud.pigx.flow.entity.ProcessInstanceRecord; +import com.pig4cloud.pigx.flow.mapper.ProcessInstanceRecordMapper; +import com.pig4cloud.pigx.flow.service.IProcessInstanceStatusEventService; +import com.pig4cloud.pigx.flow.service.IProcessNodeDataService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Optional; + +/** + * 节点任务完成通知服务 + *
+ * 该服务负责在流程节点任务完成时发送异步通知。当节点配置了外部事件回调URL时, 系统会自动调用该URL通知任务完成事件。这种机制允许流程与外部系统进行集成, + * 实现业务流程的自动化。通知采用异步方式发送,不会阻塞主流程的执行。 + *
+ * + * @author lengleng + * @date 2024/7/9 + */ +@Slf4j +@Service +@RequiredArgsConstructor +public class NodeTaskCompleteNotify { + + private final IProcessNodeDataService processNodeDataService; + + private final ProcessInstanceRecordMapper processInstanceRecordMapper; + + private final Optional+ * 当流程节点任务完成时,如果节点配置了事件通知URL,则通过HTTP POST请求 将任务完成信息发送到指定的URL。通知内容包括任务ID、处理人、处理结果等 + * 完整信息。该方法使用异步执行,确保不影响主流程的性能。通知失败时会 记录日志但不会影响流程执行。 + *
+ * @param token 安全令牌,用于在异步线程中传递认证信息 + * @param taskCompleteParamDto 任务完成参数,包含: - flowId: 流程定义ID - nodeId: 节点ID - taskId: + * 任务ID - userId: 处理人ID - result: 处理结果 - comment: 处理意见 - completeTime: 完成时间 - + * variables: 流程变量 + */ + @Async + public void sendNotify(String token, ProcessNodeRecordAssignUserParamDto taskCompleteParamDto) { + // 在异步线程中设置认证令牌 + NonWebTokenContextHolder.setToken(token); + + // 获取节点配置并发送通知 + RetOps + .of(processNodeDataService.getNodeData(taskCompleteParamDto.getFlowId(), taskCompleteParamDto.getNodeId())) + .getData() + .ifPresent(node -> { + // 验证事件配置是否为有效的URL + if (Validator.isUrl(node.getEventConfig())) { + // 发送HTTP POST请求到配置的URL + HttpResponse response = HttpRequest.post(node.getEventConfig()) + .body(JSONUtil.toJsonStr(taskCompleteParamDto)) + .timeout(10000) // 设置10秒超时 + .execute(); + log.debug("节点任务完成通知处理完成:{},数据:{}", response.getStatus(), taskCompleteParamDto); + } + }); + } + + /** + * 异步发送流程通知 + * @param token 认证令牌 + * @param instanceRecordParamDto 流程节点记录参数DTO + * @throws IllegalArgumentException 参数为空时抛出异常 + */ + public void sendFlowNotify(String token, ProcessInstanceParamDto instanceRecordParamDto) { + // 在异步线程中设置认证令牌 + NonWebTokenContextHolder.setToken(token); + if (processInstanceStatusEventServicesOptional.isEmpty()) { + return; + } + + for (IProcessInstanceStatusEventService iProcessInstanceStatusEventService : processInstanceStatusEventServicesOptional + .get()) { + + if (iProcessInstanceStatusEventService.getFlowId().equals(instanceRecordParamDto.getFlowId())) { + // 处理状态事件 + ProcessInstanceRecord processInstanceRecord = processInstanceRecordMapper.selectOne(Wrappers + .+ * 该类是流程实例管理的核心服务,负责处理流程实例的完整生命周期,主要功能包括: 1. 流程实例的启动、结束等生命周期管理 2. 待办任务、已办任务的查询 3. + * 我发起的流程、抄送给我的流程查询 4. 流程节点的格式化显示 5. 流程详情查询 + * + * 该服务整合了Flowable引擎和业务数据,为前端提供统一的流程操作接口 + *
+ * + * @author pigx code generator + * @date 2023-10-01 */ @Service @Slf4j @RequiredArgsConstructor public class ProcessInstanceServiceImpl implements IProcessInstanceService { - private final RemoteFlowEngineService flowEngineService; - private final RemoteUserService userService; + private final TaskService taskService; + + private final RuntimeService runtimeService; + + private final HistoryService historyService; + private final IProcessInstanceRecordService processInstanceRecordService; private final IProcessCopyService processCopyService; @@ -54,47 +81,117 @@ public class ProcessInstanceServiceImpl implements IProcessInstanceService { private final IProcessNodeRecordService processNodeRecordService; - private final IProcessNodeRecordAssignUserService processNodeRecordAssignUserService; - private final ObjectMapper objectMapper; /** * 启动流程 - * @param processInstanceParamDto - * @return + *+ * 根据流程定义启动一个新的流程实例。该方法会: 1. 获取当前登录用户作为流程发起人 2. 设置流程发起人信息到流程变量中 3. 调用Flowable引擎启动流程 + *
+ * @param processInstanceParamDto 流程启动参数,包含: - flowId: 流程定义ID - paramMap: 流程变量 + * @return R 启动结果,包含流程实例ID等信息 */ @Override public R startProcessInstance(ProcessInstanceParamDto processInstanceParamDto) { + // 获取当前登录用户 PigxUser user = SecurityUtils.getUser(); + // 设置流程发起人ID processInstanceParamDto.setStartUserId(String.valueOf(user.getId())); Map+ * 查询分配给当前用户的待办任务列表,并补充以下信息: 1. 流程实例的详细信息(流程名称、分组等) 2. 流程发起人信息(姓名、头像等) 3. 流程启动时间 + *
+ * @param taskQueryParamDto 查询参数,支持分页和条件过滤 + * @return R 包含分页后的待办任务列表 */ @Override public R queryMineTask(TaskQueryParamDto taskQueryParamDto) { taskQueryParamDto.setAssign(SecurityUtils.getUser().getId().toString()); - R+ * 查询当前用户已经完成的任务列表,包括: 1. 用户已审批的任务 2. 补充流程实例信息、发起人信息等 + *
+ * @param taskQueryParamDto 查询参数,支持分页和时间范围过滤 + * @return R 包含分页后的已办任务列表 */ @Override public R queryMineEndTask(TaskQueryParamDto taskQueryParamDto) { taskQueryParamDto.setAssign(SecurityUtils.getUser().getId().toString()); - R+ * 手动结束一个流程实例,通常用于: 1. 流程审批完成,正常结束 2. 流程被终止或取消 + * + * 该方法会更新流程实例记录的结束时间、状态和结束原因 + *
+ * @param processInstanceParamDto 流程实例参数,包含: - processInstanceId: 流程实例ID - paramMap: + * 可能包含approve_condition等结束原因 + * @return R 操作结果 */ @Override public R end(ProcessInstanceParamDto processInstanceParamDto) { + // 从参数中提取审批条件,用于判断流程结束原因(通过/拒绝) Optional+ * 查询当前用户发起的所有流程实例,支持: 1. 按状态过滤(进行中、已完成等) 2. 按时间范围过滤 3. 分页查询 + *
+ * @param taskQueryParamDto 查询条件,包含状态、时间范围、分页参数 + * @return R 包含分页后的流程实例列表 */ @Override public R queryMineStarted(TaskQueryParamDto taskQueryParamDto) { @@ -252,9 +417,12 @@ public class ProcessInstanceServiceImpl implements IProcessInstanceService { } /** - * 查询抄送给我的 - * @param taskQueryParamDto 查询参数 - * @return + * 查询抄送给我的流程 + *+ * 查询抄送给当前用户的流程列表。抄送功能允许流程参与者将流程信息 通知给其他相关人员,被抄送人可以查看流程但不参与审批 + *
+ * @param taskQueryParamDto 查询参数,支持时间范围过滤和分页 + * @return R 包含分页后的抄送记录,包括发起人信息 */ @Override public R queryMineCC(TaskQueryParamDto taskQueryParamDto) { @@ -288,16 +456,21 @@ public class ProcessInstanceServiceImpl implements IProcessInstanceService { } Page p = BeanUtil.copyProperties(page, Page.class); - p.setRecords(processCopyVoList); - return R.ok(p); } /** * 格式化流程显示 - * @param nodeFormatParamVo - * @return + *+ * 将流程定义数据格式化为前端可展示的节点结构,主要功能: 1. 解析流程定义的JSON数据 2. 标记已完成的节点 3. 根据流程变量计算条件节点的显示状态 4. + * 处理节点权限和表单权限 + * + * 该方法用于流程图的可视化展示 + *
+ * @param nodeFormatParamVo 格式化参数,包含: - flowId: 流程定义ID - processInstanceId: 流程实例ID - + * taskId: 任务ID(可选) - paramMap: 流程变量 + * @return R 包含格式化后的节点列表 */ @SneakyThrows @Override @@ -319,29 +492,22 @@ public class ProcessInstanceServiceImpl implements IProcessInstanceService { if (StrUtil.isNotBlank(nodeFormatParamVo.getTaskId())) { VariableQueryParamDto variableQueryParamDto = new VariableQueryParamDto(); variableQueryParamDto.setTaskId(nodeFormatParamVo.getTaskId()); - R