mirror of
				https://gitee.com/hhyykk/ipms-sjy.git
				synced 2025-10-31 18:28:43 +08:00 
			
		
		
		
	BPM:支持多表单,每个流程任务都可以绑定流程表单
This commit is contained in:
		| @@ -6,6 +6,8 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; | ||||
| import cn.iocoder.yudao.framework.common.util.number.NumberUtils; | ||||
| import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.*; | ||||
| import cn.iocoder.yudao.module.bpm.convert.task.BpmTaskConvert; | ||||
| import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO; | ||||
| import cn.iocoder.yudao.module.bpm.service.definition.BpmFormService; | ||||
| import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService; | ||||
| import cn.iocoder.yudao.module.bpm.service.task.BpmTaskService; | ||||
| import cn.iocoder.yudao.module.system.api.dept.DeptApi; | ||||
| @@ -46,6 +48,8 @@ public class BpmTaskController { | ||||
|     private BpmTaskService taskService; | ||||
|     @Resource | ||||
|     private BpmProcessInstanceService processInstanceService; | ||||
|     @Resource | ||||
|     private BpmFormService formService; | ||||
|  | ||||
|     @Resource | ||||
|     private AdminUserApi adminUserApi; | ||||
| @@ -98,7 +102,11 @@ public class BpmTaskController { | ||||
|         Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(userIds); | ||||
|         Map<Long, DeptRespDTO> deptMap = deptApi.getDeptMap( | ||||
|                 convertSet(userMap.values(), AdminUserRespDTO::getDeptId)); | ||||
|         return success(BpmTaskConvert.INSTANCE.buildTaskListByProcessInstanceId(taskList, processInstance, userMap, deptMap)); | ||||
|         // 获得 Form Map | ||||
|         Map<Long, BpmFormDO> formMap = formService.getFormMap( | ||||
|                 convertSet(taskList, task -> Long.parseLong(task.getFormKey()))); | ||||
|         return success(BpmTaskConvert.INSTANCE.buildTaskListByProcessInstanceId(taskList, processInstance, | ||||
|                 formMap, userMap, deptMap)); | ||||
|     } | ||||
|  | ||||
|     @PutMapping("/approve") | ||||
|   | ||||
| @@ -15,7 +15,7 @@ public class BpmProcessInstanceCreateReqVO { | ||||
|     @NotEmpty(message = "流程定义编号不能为空") | ||||
|     private String processDefinitionId; | ||||
|  | ||||
|     @Schema(description = "变量实例") | ||||
|     @Schema(description = "变量实例(动态表单)") | ||||
|     private Map<String, Object> variables; | ||||
|  | ||||
|     // TODO @hai:assignees 复数 | ||||
|   | ||||
| @@ -5,6 +5,7 @@ import jakarta.validation.constraints.NotEmpty; | ||||
| import lombok.Data; | ||||
|  | ||||
| import java.util.Collection; | ||||
| import java.util.Map; | ||||
|  | ||||
| @Schema(description = "管理后台 - 通过流程任务的 Request VO") | ||||
| @Data | ||||
| @@ -21,4 +22,7 @@ public class BpmTaskApproveReqVO { | ||||
|     @Schema(description = "抄送的用户编号数组", requiredMode = Schema.RequiredMode.REQUIRED, example = "1,2") | ||||
|     private Collection<Long> copyUserIds; | ||||
|  | ||||
|     @Schema(description = "变量实例(动态表单)", requiredMode = Schema.RequiredMode.REQUIRED) | ||||
|     private Map<String, Object> variables; | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -6,6 +6,7 @@ import lombok.Data; | ||||
|  | ||||
| import java.time.LocalDateTime; | ||||
| import java.util.List; | ||||
| import java.util.Map; | ||||
|  | ||||
| @Schema(description = "管理后台 - 流程任务 Response VO") | ||||
| @Data | ||||
| @@ -49,7 +50,6 @@ public class BpmTaskRespVO { | ||||
|  | ||||
|     @Schema(description = "所属流程实例编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "8888") | ||||
|     private String processInstanceId; | ||||
|  | ||||
|     /** | ||||
|      * 所属流程实例 | ||||
|      */ | ||||
| @@ -57,10 +57,20 @@ public class BpmTaskRespVO { | ||||
|  | ||||
|     @Schema(description = "父任务编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") | ||||
|     private String parentTaskId; | ||||
|  | ||||
|     @Schema(description = "子任务列表(由加签生成)", requiredMode = Schema.RequiredMode.REQUIRED, example = "childrenTask") | ||||
|     private List<BpmTaskRespVO> children; | ||||
|  | ||||
|     @Schema(description = "表单编号", example = "1024") | ||||
|     private Long formId; | ||||
|     @Schema(description = "表单名字", example = "请假表单") | ||||
|     private String formName; | ||||
|     @Schema(description = "表单的配置-JSON 字符串") | ||||
|     private String formConf; | ||||
|     @Schema(description = "表单项的数组") | ||||
|     private List<String> formFields; | ||||
|     @Schema(description = "提交的表单值", requiredMode = Schema.RequiredMode.REQUIRED) | ||||
|     private Map<String, Object> formVariables; | ||||
|  | ||||
|     @Data | ||||
|     @Schema(description = "流程实例") | ||||
|     public static class ProcessInstance { | ||||
|   | ||||
| @@ -1,5 +1,6 @@ | ||||
| package cn.iocoder.yudao.module.bpm.convert.definition; | ||||
|  | ||||
| import cn.hutool.core.util.ArrayUtil; | ||||
| import cn.hutool.core.util.StrUtil; | ||||
| import cn.iocoder.yudao.framework.common.pojo.PageResult; | ||||
| import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; | ||||
| @@ -56,7 +57,9 @@ public interface BpmModelConvert { | ||||
|                                      byte[] bpmnBytes) { | ||||
|         BpmModelMetaInfoRespDTO metaInfo = JsonUtils.parseObject(model.getMetaInfo(), BpmModelMetaInfoRespDTO.class); | ||||
|         BpmModelRespVO modelVO = buildModel0(model, metaInfo, null, null, null, null); | ||||
|         modelVO.setBpmnXml(new String(bpmnBytes)); | ||||
|         if (ArrayUtil.isNotEmpty(bpmnBytes)) { | ||||
|             modelVO.setBpmnXml(new String(bpmnBytes)); | ||||
|         } | ||||
|         return modelVO; | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -2,15 +2,14 @@ package cn.iocoder.yudao.module.bpm.convert.task; | ||||
|  | ||||
| import cn.iocoder.yudao.framework.common.pojo.PageResult; | ||||
| import cn.iocoder.yudao.framework.common.util.collection.MapUtils; | ||||
| import cn.iocoder.yudao.framework.common.util.date.DateUtils; | ||||
| import cn.iocoder.yudao.framework.common.util.number.NumberUtils; | ||||
| import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | ||||
| import cn.iocoder.yudao.framework.flowable.core.util.FlowableUtils; | ||||
| import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstancePageItemRespVO; | ||||
| import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceRespVO; | ||||
| import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmCategoryDO; | ||||
| import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionInfoDO; | ||||
| import cn.iocoder.yudao.module.bpm.event.BpmProcessInstanceResultEvent; | ||||
| import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmConstants; | ||||
| import cn.iocoder.yudao.module.bpm.service.message.dto.BpmMessageSendWhenProcessInstanceApproveReqDTO; | ||||
| import cn.iocoder.yudao.module.bpm.service.message.dto.BpmMessageSendWhenProcessInstanceRejectReqDTO; | ||||
| import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; | ||||
| @@ -19,7 +18,6 @@ import org.flowable.engine.history.HistoricProcessInstance; | ||||
| import org.flowable.engine.repository.ProcessDefinition; | ||||
| import org.flowable.engine.runtime.ProcessInstance; | ||||
| import org.flowable.task.api.Task; | ||||
| import org.mapstruct.Mapper; | ||||
| import org.mapstruct.Mapping; | ||||
| import org.mapstruct.MappingTarget; | ||||
| import org.mapstruct.factory.Mappers; | ||||
| @@ -32,7 +30,6 @@ import java.util.Map; | ||||
|  * | ||||
|  * @author 芋道源码 | ||||
|  */ | ||||
| @Mapper(uses = DateUtils.class) | ||||
| public interface BpmProcessInstanceConvert { | ||||
|  | ||||
|     BpmProcessInstanceConvert INSTANCE = Mappers.getMapper(BpmProcessInstanceConvert.class); | ||||
| @@ -44,7 +41,7 @@ public interface BpmProcessInstanceConvert { | ||||
|         PageResult<BpmProcessInstancePageItemRespVO> vpPageResult = BeanUtils.toBean(pageResult, BpmProcessInstancePageItemRespVO.class); | ||||
|         for (int i = 0; i < pageResult.getList().size(); i++) { | ||||
|             BpmProcessInstancePageItemRespVO respVO = vpPageResult.getList().get(i); | ||||
|             respVO.setStatus((Integer) pageResult.getList().get(i).getProcessVariables().get(BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS)); | ||||
|             respVO.setStatus(FlowableUtils.getProcessInstanceStatus(pageResult.getList().get(i))); | ||||
|             MapUtils.findAndThen(processDefinitionMap, respVO.getProcessDefinitionId(), | ||||
|                     processDefinition -> respVO.setCategory(processDefinition.getCategory())); | ||||
|             MapUtils.findAndThen(categoryMap, respVO.getCategory(), category -> respVO.setCategoryName(category.getName())); | ||||
| @@ -57,8 +54,8 @@ public interface BpmProcessInstanceConvert { | ||||
|                                               ProcessDefinition processDefinition, BpmProcessDefinitionInfoDO processDefinitionExt, | ||||
|                                               String bpmnXml, AdminUserRespDTO startUser, DeptRespDTO dept) { | ||||
|         BpmProcessInstanceRespVO respVO = convert2(processInstance); | ||||
|         respVO.setStatus((Integer) processInstance.getProcessVariables().get(BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS)); | ||||
|         respVO.setFormVariables(processInstance.getProcessVariables()); // TODO 芋艿:真的这么搞么???formVariable 要不要换个 key 之类的 | ||||
|         respVO.setStatus(FlowableUtils.getProcessInstanceStatus(processInstance)); | ||||
|         respVO.setFormVariables(FlowableUtils.filterProcessInstanceFormVariable(processInstance.getProcessVariables())); | ||||
|         // definition | ||||
|         respVO.setProcessDefinition(convert2(processDefinition)); | ||||
|         copyTo(processDefinitionExt, respVO.getProcessDefinition()); | ||||
|   | ||||
| @@ -1,14 +1,15 @@ | ||||
| package cn.iocoder.yudao.module.bpm.convert.task; | ||||
|  | ||||
| import cn.hutool.core.map.MapUtil; | ||||
| import cn.hutool.core.util.StrUtil; | ||||
| import cn.iocoder.yudao.framework.common.pojo.PageResult; | ||||
| import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; | ||||
| import cn.iocoder.yudao.framework.common.util.date.DateUtils; | ||||
| import cn.iocoder.yudao.framework.common.util.number.NumberUtils; | ||||
| import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | ||||
| import cn.iocoder.yudao.framework.flowable.core.util.FlowableUtils; | ||||
| import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceRespVO; | ||||
| import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskRespVO; | ||||
| import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmConstants; | ||||
| import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO; | ||||
| import cn.iocoder.yudao.module.bpm.service.message.dto.BpmMessageSendWhenTaskCreatedReqDTO; | ||||
| import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; | ||||
| import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; | ||||
| @@ -17,7 +18,6 @@ import org.flowable.engine.runtime.ProcessInstance; | ||||
| import org.flowable.task.api.Task; | ||||
| import org.flowable.task.api.history.HistoricTaskInstance; | ||||
| import org.flowable.task.service.impl.persistence.entity.TaskEntityImpl; | ||||
| import org.mapstruct.Mapper; | ||||
| import org.mapstruct.factory.Mappers; | ||||
|  | ||||
| import java.util.Date; | ||||
| @@ -25,13 +25,13 @@ import java.util.List; | ||||
| import java.util.Map; | ||||
|  | ||||
| import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; | ||||
| import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen; | ||||
|  | ||||
| /** | ||||
|  * Bpm 任务 Convert | ||||
|  * | ||||
|  * @author 芋道源码 | ||||
|  */ | ||||
| @Mapper(uses = DateUtils.class) | ||||
| public interface BpmTaskConvert { | ||||
|  | ||||
|     BpmTaskConvert INSTANCE = Mappers.getMapper(BpmTaskConvert.class); | ||||
| @@ -45,8 +45,7 @@ public interface BpmTaskConvert { | ||||
|                 return; | ||||
|             } | ||||
|             AdminUserRespDTO startUser = userMap.get(NumberUtils.parseLong(processInstance.getStartUserId())); | ||||
|             taskVO.setProcessInstance(BeanUtils.toBean(processInstance, BpmTaskRespVO.ProcessInstance.class, | ||||
|                     processInstanceVO -> processInstanceVO.setStartUser(BeanUtils.toBean(startUser, BpmProcessInstanceRespVO.User.class)))); | ||||
|             taskVO.getProcessInstance().setStartUser(BeanUtils.toBean(startUser, BpmProcessInstanceRespVO.User.class)); | ||||
|         }); | ||||
|     } | ||||
|  | ||||
| @@ -55,14 +54,13 @@ public interface BpmTaskConvert { | ||||
|                                                         Map<Long, AdminUserRespDTO> userMap) { | ||||
|         List<BpmTaskRespVO> taskVOList = CollectionUtils.convertList(pageResult.getList(), task -> { | ||||
|             BpmTaskRespVO taskVO = BeanUtils.toBean(task, BpmTaskRespVO.class); | ||||
|             taskVO.setStatus((Integer) task.getTaskLocalVariables().get(BpmConstants.TASK_VARIABLE_STATUS)); | ||||
|             taskVO.setReason((String) task.getTaskLocalVariables().get(BpmConstants.TASK_VARIABLE_REASON)); | ||||
|             taskVO.setStatus(FlowableUtils.getTaskStatus(task)).setReason(FlowableUtils.getTaskReason(task)); | ||||
|             // 流程实例 | ||||
|             HistoricProcessInstance processInstance = processInstanceMap.get(taskVO.getProcessInstanceId()); | ||||
|             if (processInstance != null) { | ||||
|                 AdminUserRespDTO startUser = userMap.get(NumberUtils.parseLong(processInstance.getStartUserId())); | ||||
|                 taskVO.setProcessInstance(BeanUtils.toBean(processInstance, BpmTaskRespVO.ProcessInstance.class, | ||||
|                         processInstanceVO -> processInstanceVO.setStartUser(BeanUtils.toBean(startUser, BpmProcessInstanceRespVO.User.class)))); | ||||
|                 taskVO.setProcessInstance(BeanUtils.toBean(processInstance, BpmTaskRespVO.ProcessInstance.class)); | ||||
|                 taskVO.getProcessInstance().setStartUser(BeanUtils.toBean(startUser, BpmProcessInstanceRespVO.User.class)); | ||||
|             } | ||||
|             return taskVO; | ||||
|         }); | ||||
| @@ -71,32 +69,32 @@ public interface BpmTaskConvert { | ||||
|  | ||||
|     default List<BpmTaskRespVO> buildTaskListByProcessInstanceId(List<HistoricTaskInstance> taskList, | ||||
|                                                                  HistoricProcessInstance processInstance, | ||||
|                                                                  Map<Long, BpmFormDO> formMap, | ||||
|                                                                  Map<Long, AdminUserRespDTO> userMap, | ||||
|                                                                  Map<Long, DeptRespDTO> deptMap) { | ||||
|         List<BpmTaskRespVO> taskVOList = CollectionUtils.convertList(taskList, task -> { | ||||
|             BpmTaskRespVO taskVO = BeanUtils.toBean(task, BpmTaskRespVO.class); | ||||
|             taskVO.setStatus((Integer) task.getTaskLocalVariables().get(BpmConstants.TASK_VARIABLE_STATUS)); | ||||
|             taskVO.setReason((String) task.getTaskLocalVariables().get(BpmConstants.TASK_VARIABLE_REASON)); | ||||
|             taskVO.setStatus(FlowableUtils.getTaskStatus(task)).setReason(FlowableUtils.getTaskReason(task)); | ||||
|             // 流程实例 | ||||
|             AdminUserRespDTO startUser = userMap.get(NumberUtils.parseLong(processInstance.getStartUserId())); | ||||
|             taskVO.setProcessInstance(BeanUtils.toBean(processInstance, BpmTaskRespVO.ProcessInstance.class, | ||||
|                     processInstanceVO -> processInstanceVO.setStartUser(BeanUtils.toBean(startUser, BpmProcessInstanceRespVO.User.class)))); | ||||
|             taskVO.setProcessInstance(BeanUtils.toBean(processInstance, BpmTaskRespVO.ProcessInstance.class)); | ||||
|             taskVO.getProcessInstance().setStartUser(BeanUtils.toBean(startUser, BpmProcessInstanceRespVO.User.class)); | ||||
|             // 表单信息 | ||||
|             BpmFormDO form = MapUtil.get(formMap, Long.parseLong(task.getFormKey()), BpmFormDO.class); | ||||
|             if (form != null) { | ||||
|                 taskVO.setFormId(form.getId()).setFormName(form.getName()).setFormConf(form.getConf()) | ||||
|                         .setFormFields(form.getFields()).setFormVariables(FlowableUtils.getTaskFormVariable(task)); | ||||
|             } | ||||
|             // 用户信息 | ||||
|             AdminUserRespDTO assignUser = userMap.get(NumberUtils.parseLong(task.getAssignee())); | ||||
|             if (assignUser != null) { | ||||
|                 taskVO.setAssigneeUser(BeanUtils.toBean(assignUser, BpmProcessInstanceRespVO.User.class)); | ||||
|                 DeptRespDTO dept = deptMap.get(assignUser.getDeptId()); | ||||
|                 if (dept != null) { | ||||
|                     taskVO.getAssigneeUser().setDeptName(dept.getName()); | ||||
|                 } | ||||
|                 findAndThen(deptMap, assignUser.getDeptId(), dept -> taskVO.getAssigneeUser().setDeptName(dept.getName())); | ||||
|             } | ||||
|             AdminUserRespDTO ownerUser = userMap.get(NumberUtils.parseLong(task.getOwner())); | ||||
|             if (ownerUser != null) { | ||||
|                 taskVO.setOwnerUser(BeanUtils.toBean(ownerUser, BpmProcessInstanceRespVO.User.class)); | ||||
|                 DeptRespDTO dept = deptMap.get(ownerUser.getDeptId()); | ||||
|                 if (dept != null) { | ||||
|                     taskVO.getOwnerUser().setDeptName(dept.getName()); | ||||
|                 } | ||||
|                 findAndThen(deptMap, ownerUser.getDeptId(), dept -> taskVO.getOwnerUser().setDeptName(dept.getName())); | ||||
|             } | ||||
|             return taskVO; | ||||
|         }); | ||||
| @@ -126,10 +124,7 @@ public interface BpmTaskConvert { | ||||
|             AdminUserRespDTO ownerUser = userMap.get(NumberUtils.parseLong(task.getOwner())); | ||||
|             if (ownerUser != null) { | ||||
|                 taskVO.setOwnerUser(BeanUtils.toBean(ownerUser, BpmProcessInstanceRespVO.User.class)); | ||||
|                 DeptRespDTO dept = deptMap.get(ownerUser.getDeptId()); | ||||
|                 if (dept != null) { | ||||
|                     taskVO.getOwnerUser().setDeptName(dept.getName()); | ||||
|                 } | ||||
|                 findAndThen(deptMap, ownerUser.getDeptId(), dept -> taskVO.getOwnerUser().setDeptName(dept.getName())); | ||||
|             } | ||||
|         })); | ||||
|     } | ||||
|   | ||||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| @@ -10,6 +10,7 @@ import cn.iocoder.yudao.framework.common.util.date.DateUtils; | ||||
| import cn.iocoder.yudao.framework.common.util.number.NumberUtils; | ||||
| import cn.iocoder.yudao.framework.common.util.object.PageUtils; | ||||
| import cn.iocoder.yudao.framework.flowable.core.util.BpmnModelUtils; | ||||
| import cn.iocoder.yudao.framework.flowable.core.util.FlowableUtils; | ||||
| import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils; | ||||
| import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.*; | ||||
| import cn.iocoder.yudao.module.bpm.convert.task.BpmTaskConvert; | ||||
| @@ -185,7 +186,9 @@ public class BpmTaskServiceImpl implements BpmTaskService { | ||||
|         taskService.addComment(task.getId(), task.getProcessInstanceId(), BpmCommentTypeEnum.APPROVE.getType(), | ||||
|                 BpmCommentTypeEnum.APPROVE.formatComment(reqVO.getReason())); | ||||
|         // 3.3 调用 BPM complete 去完成任务 | ||||
|         taskService.complete(task.getId(), instance.getProcessVariables()); | ||||
|         // 其中,variables 是存储动态表单到 local 任务级别。过滤一下,避免 ProcessInstance 系统级的变量被占用 | ||||
|         Map<String, Object> variables = FlowableUtils.filterTaskFormVariable(reqVO.getVariables()); | ||||
|         taskService.complete(task.getId(), variables, true); | ||||
|  | ||||
|         // 【加签专属】处理加签任务 | ||||
|         handleParentTaskIfSign(task.getParentTaskId()); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 YunaiV
					YunaiV