工作流 Flowable 流程实例 相关实现

This commit is contained in:
jason 2022-02-11 21:54:39 +08:00
parent d64555697f
commit c761f5258a
17 changed files with 822 additions and 0 deletions

View File

@ -2,8 +2,10 @@ package cn.iocoder.yudao.module.bpm.controller.admin.definition;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionListReqVO;
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionPageItemRespVO;
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionPageReqVO;
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionRespVO;
import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
@ -17,6 +19,8 @@ import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.List;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@Api(tags = "管理后台 - 流程定义")
@ -36,6 +40,14 @@ public class BpmProcessDefinitionController {
return success(bpmDefinitionService.getProcessDefinitionPage(pageReqVO));
}
@GetMapping ("/list")
@ApiOperation(value = "获得流程定义列表")
@PreAuthorize("@ss.hasPermission('bpm:process-definition:query')")
public CommonResult<List<BpmProcessDefinitionRespVO>> getProcessDefinitionList(
BpmProcessDefinitionListReqVO listReqVO) {
return success(bpmDefinitionService.getProcessDefinitionList(listReqVO));
}
@GetMapping ("/get-bpmn-xml")
@ApiOperation(value = "获得流程定义的 BPMN XML")
@ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = String.class)

View File

@ -0,0 +1,59 @@
package cn.iocoder.yudao.module.bpm.controller.admin.definition;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule.BpmTaskAssignRuleCreateReqVO;
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule.BpmTaskAssignRuleRespVO;
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule.BpmTaskAssignRuleUpdateReqVO;
import cn.iocoder.yudao.module.bpm.service.definition.BpmTaskAssignRuleService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.validation.Valid;
import java.util.List;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@Api(tags = "管理后台 - 任务分配规则")
@RestController
@RequestMapping("/bpm/task-assign-rule")
@Validated
public class BpmTaskAssignRuleController {
@Resource
private BpmTaskAssignRuleService taskAssignRuleService;
@GetMapping("/list")
@ApiOperation(value = "获得任务分配规则列表")
@ApiImplicitParams({
@ApiImplicitParam(name = "modelId", value = "模型编号", example = "1024", dataTypeClass = String.class),
@ApiImplicitParam(name = "processDefinitionId", value = "流程定义的编号", example = "2048", dataTypeClass = String.class)
})
@PreAuthorize("@ss.hasPermission('bpm:task-assign-rule:query')")
public CommonResult<List<BpmTaskAssignRuleRespVO>> getTaskAssignRuleList(
@RequestParam(value = "modelId", required = false) String modelId,
@RequestParam(value = "processDefinitionId", required = false) String processDefinitionId) {
return success(taskAssignRuleService.getTaskAssignRuleList(modelId, processDefinitionId));
}
@PostMapping("/create")
@ApiOperation(value = "创建任务分配规则")
@PreAuthorize("@ss.hasPermission('bpm:task-assign-rule:create')")
public CommonResult<Long> createTaskAssignRule(@Valid @RequestBody BpmTaskAssignRuleCreateReqVO reqVO) {
return success(taskAssignRuleService.createTaskAssignRule(reqVO));
}
@PutMapping("/update")
@ApiOperation(value = "更新任务分配规则")
@PreAuthorize("@ss.hasPermission('bpm:task-assign-rule:update')")
public CommonResult<Boolean> updateTaskAssignRule(@Valid @RequestBody BpmTaskAssignRuleUpdateReqVO reqVO) {
taskAssignRuleService.updateTaskAssignRule(reqVO);
return success(true);
}
}

View File

@ -0,0 +1,53 @@
package cn.iocoder.yudao.module.bpm.controller.admin.task;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCreateReqVO;
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceMyPageReqVO;
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.service.task.BpmProcessInstanceService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.validation.Valid;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
@Api(tags = "管理后台 - 流程实例") // 流程实例通过流程定义创建的一次申请
@RestController
@RequestMapping("/bpm/process-instance")
@Validated
public class BpmProcessInstanceController {
@Resource
private BpmProcessInstanceService processInstanceService;
@GetMapping("/my-page")
@ApiOperation(value = "获得我的实例分页列表", notes = "在【我的流程】菜单中,进行调用")
@PreAuthorize("@ss.hasPermission('bpm:process-instance:query')")
public CommonResult<PageResult<BpmProcessInstancePageItemRespVO>> getMyProcessInstancePage(
@Valid BpmProcessInstanceMyPageReqVO pageReqVO) {
return success(processInstanceService.getMyProcessInstancePage(getLoginUserId(), pageReqVO));
}
@PostMapping("/create")
@ApiOperation("新建流程实例")
@PreAuthorize("@ss.hasPermission('bpm:process-instance:query')")
public CommonResult<String> createProcessInstance(@Valid @RequestBody BpmProcessInstanceCreateReqVO createReqVO) {
return success(processInstanceService.createProcessInstance(getLoginUserId(), createReqVO));
}
@GetMapping("/get")
@ApiOperation(value = "获得指定流程实例", notes = "在【流程详细】界面中,进行调用")
@ApiImplicitParam(name = "id", value = "流程实例的编号", required = true, dataTypeClass = String.class)
@PreAuthorize("@ss.hasPermission('bpm:process-instance:query')")
public CommonResult<BpmProcessInstanceRespVO> getProcessInstance(@RequestParam("id") String id) {
return success(processInstanceService.getProcessInstanceVO(id));
}
}

View File

@ -0,0 +1,39 @@
package cn.iocoder.yudao.module.bpm.controller.admin.task;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskTodoPageItemRespVO;
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskTodoPageReqVO;
import cn.iocoder.yudao.module.bpm.service.task.BpmTaskService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.engine.TaskService;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import javax.validation.Valid;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLoginUserId;
@Api(tags = "管理后台 - 流程任务实例")
@RestController
@RequestMapping("/bpm/task")
@Validated
public class BpmTaskController {
@Resource
private BpmTaskService taskService;
@GetMapping("todo-page")
@ApiOperation("获取 Todo 待办任务分页")
@PreAuthorize("@ss.hasPermission('bpm:task:query')")
public CommonResult<PageResult<BpmTaskTodoPageItemRespVO>> getTodoTaskPage(@Valid BpmTaskTodoPageReqVO pageVO) {
return success(taskService.getTodoTaskPage(getLoginUserId(), pageVO));
}
}

View File

@ -12,6 +12,7 @@ import org.flowable.engine.repository.ProcessDefinition;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.MappingTarget;
import org.mapstruct.Named;
import org.mapstruct.factory.Mappers;
import java.util.List;
@ -41,6 +42,26 @@ public interface BpmProcessDefinitionConvert {
});
}
default List<BpmProcessDefinitionRespVO> convertList3(List<ProcessDefinition> list,
Map<String, BpmProcessDefinitionExtDO> processDefinitionDOMap) {
return CollectionUtils.convertList(list, processDefinition -> {
BpmProcessDefinitionRespVO respVO = convert3(processDefinition);
BpmProcessDefinitionExtDO processDefinitionExtDO = processDefinitionDOMap.get(processDefinition.getId());
// 复制通用属性
copyTo(processDefinitionExtDO, respVO);
return respVO;
});
}
@Mapping(source = "suspended", target = "suspensionState", qualifiedByName = "convertSuspendedToSuspensionState")
BpmProcessDefinitionRespVO convert3(ProcessDefinition bean);
@Named("convertSuspendedToSuspensionState")
default Integer convertSuspendedToSuspensionState(boolean suspended) {
return suspended ? SuspensionState.SUSPENDED.getStateCode() :
SuspensionState.ACTIVE.getStateCode();
}
default BpmProcessDefinitionPageItemRespVO convert(ProcessDefinition bean, Deployment deployment,
BpmProcessDefinitionExtDO processDefinitionExtDO, BpmFormDO form) {
BpmProcessDefinitionPageItemRespVO respVO = convert(bean);

View File

@ -0,0 +1,76 @@
package cn.iocoder.yudao.module.bpm.convert.task;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
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.BpmProcessDefinitionExtDO;
import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmProcessInstanceExtDO;
import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.task.api.Task;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.MappingTarget;
import org.mapstruct.factory.Mappers;
import java.util.List;
import java.util.Map;
/**
* 流程实例 Convert
*
* @author 芋道源码
*/
@Mapper
public interface BpmProcessInstanceConvert {
BpmProcessInstanceConvert INSTANCE = Mappers.getMapper(BpmProcessInstanceConvert.class);
default PageResult<BpmProcessInstancePageItemRespVO> convertPage(PageResult<BpmProcessInstanceExtDO> page,
Map<String, List<Task>> taskMap) {
List<BpmProcessInstancePageItemRespVO> list = convertList(page.getList());
list.forEach(respVO -> respVO.setTasks(convertList2(taskMap.get(respVO.getId()))));
return new PageResult<>(list, page.getTotal());
}
List<BpmProcessInstancePageItemRespVO> convertList(List<BpmProcessInstanceExtDO> list);
List<BpmProcessInstancePageItemRespVO.Task> convertList2(List<Task> tasks);
default BpmProcessInstanceRespVO convert2(HistoricProcessInstance processInstance, BpmProcessInstanceExtDO processInstanceExt,
ProcessDefinition processDefinition, BpmProcessDefinitionExtDO processDefinitionExt,
String bpmnXml, AdminUserRespDTO startUser, DeptRespDTO dept) {
BpmProcessInstanceRespVO respVO = convert2(processInstance);
copyTo(processInstanceExt, respVO);
// definition
respVO.setProcessDefinition(convert2(processDefinition));
copyTo(processDefinitionExt, respVO.getProcessDefinition());
respVO.getProcessDefinition().setBpmnXml(bpmnXml);
// user
if (startUser != null) {
respVO.setStartUser(convert2(startUser));
if (dept != null) {
respVO.getStartUser().setDeptName(dept.getName());
}
}
return respVO;
}
BpmProcessInstanceRespVO convert2(HistoricProcessInstance bean);
@Mapping(source = "from.id", target = "to.id", ignore = true)
void copyTo(BpmProcessInstanceExtDO from, @MappingTarget BpmProcessInstanceRespVO to);
BpmProcessInstanceRespVO.ProcessDefinition convert2(ProcessDefinition bean);
@Mapping(source = "from.id", target = "to.id", ignore = true)
void copyTo(BpmProcessDefinitionExtDO from, @MappingTarget BpmProcessInstanceRespVO.ProcessDefinition to);
BpmProcessInstanceRespVO.User convert2(AdminUserRespDTO bean);
}

View File

@ -0,0 +1,68 @@
package cn.iocoder.yudao.module.bpm.convert.task;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskDonePageItemRespVO;
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskRespVO;
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskTodoPageItemRespVO;
import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmTaskExtDO;
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;
import org.flowable.common.engine.impl.db.SuspensionState;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.task.api.Task;
import org.flowable.task.api.history.HistoricTaskInstance;
import org.mapstruct.*;
import org.mapstruct.factory.Mappers;
import java.util.List;
import java.util.Map;
/**
* Bpm 任务 Convert
*
* @author 芋道源码
*/
@Mapper
public interface BpmTaskConvert {
BpmTaskConvert INSTANCE = Mappers.getMapper(BpmTaskConvert.class);
default List<BpmTaskTodoPageItemRespVO> convertList1(List<Task> tasks, Map<String, ProcessInstance> processInstanceMap,
Map<Long, AdminUserRespDTO> userMap) {
return CollectionUtils.convertList(tasks, task -> {
BpmTaskTodoPageItemRespVO respVO = convert1(task);
ProcessInstance processInstance = processInstanceMap.get(task.getProcessInstanceId());
if (processInstance != null) {
AdminUserRespDTO startUser = userMap.get(NumberUtils.parseLong(processInstance.getStartUserId()));
respVO.setProcessInstance(convert(processInstance, startUser));
}
return respVO;
});
}
@Mapping(source = "suspended", target = "suspensionState", qualifiedByName = "convertSuspendedToSuspensionState")
BpmTaskTodoPageItemRespVO convert1(Task bean);
@Named("convertSuspendedToSuspensionState")
default Integer convertSuspendedToSuspensionState(boolean suspended) {
return suspended ? SuspensionState.SUSPENDED.getStateCode() :
SuspensionState.ACTIVE.getStateCode();
}
@Mappings({
@Mapping(source = "processInstance.id", target = "id"),
@Mapping(source = "processInstance.name", target = "name"),
@Mapping(source = "processInstance.startUserId", target = "startUserId"),
@Mapping(source = "processInstance.processDefinitionId", target = "processDefinitionId"),
@Mapping(source = "startUser.nickname", target = "startUserNickname")
})
BpmTaskTodoPageItemRespVO.ProcessInstance convert(ProcessInstance processInstance, AdminUserRespDTO startUser);
}

View File

@ -2,8 +2,10 @@ package cn.iocoder.yudao.module.bpm.service.definition;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionListReqVO;
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionPageItemRespVO;
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionPageReqVO;
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionRespVO;
import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionExtDO;
import cn.iocoder.yudao.module.bpm.service.definition.dto.BpmProcessDefinitionCreateReqDTO;
import org.flowable.bpmn.model.BpmnModel;
@ -31,6 +33,14 @@ public interface BpmProcessDefinitionService {
*/
PageResult<BpmProcessDefinitionPageItemRespVO> getProcessDefinitionPage(BpmProcessDefinitionPageReqVO pageReqVO);
/**
* 获得流程定义列表
*
* @param listReqVO 列表入参
* @return 流程定义列表
*/
List<BpmProcessDefinitionRespVO> getProcessDefinitionList(BpmProcessDefinitionListReqVO listReqVO);
/**
* 创建流程定义
*

View File

@ -5,8 +5,10 @@ import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.PageUtils;
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionListReqVO;
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionPageItemRespVO;
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionPageReqVO;
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionRespVO;
import cn.iocoder.yudao.module.bpm.convert.definition.BpmProcessDefinitionConvert;
import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO;
import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionExtDO;
@ -228,6 +230,27 @@ public class BpmProcessDefinitionServiceImpl implements BpmProcessDefinitionServ
return processDefinitionMapper.selectByProcessDefinitionId(id);
}
@Override
public List<BpmProcessDefinitionRespVO> getProcessDefinitionList(BpmProcessDefinitionListReqVO listReqVO) {
// 拼接查询条件
ProcessDefinitionQuery definitionQuery = repositoryService.createProcessDefinitionQuery();
if (Objects.equals(SuspensionState.SUSPENDED.getStateCode(), listReqVO.getSuspensionState())) {
definitionQuery.suspended();
} else if (Objects.equals(SuspensionState.ACTIVE.getStateCode(), listReqVO.getSuspensionState())) {
definitionQuery.active();
}
// 执行查询
List<ProcessDefinition> processDefinitions = definitionQuery.list();
// 获得 BpmProcessDefinitionDO Map
List<BpmProcessDefinitionExtDO> processDefinitionDOs = processDefinitionMapper.selectListByProcessDefinitionIds(
convertList(processDefinitions, ProcessDefinition::getId));
Map<String, BpmProcessDefinitionExtDO> processDefinitionDOMap = convertMap(processDefinitionDOs,
BpmProcessDefinitionExtDO::getProcessDefinitionId);
// 执行查询并返回
return BpmProcessDefinitionConvert.INSTANCE.convertList3(processDefinitions, processDefinitionDOMap);
}
@Override
public PageResult<BpmProcessDefinitionPageItemRespVO> getProcessDefinitionPage(BpmProcessDefinitionPageReqVO pageVO) {
ProcessDefinitionQuery definitionQuery = repositoryService.createProcessDefinitionQuery();
@ -262,4 +285,6 @@ public class BpmProcessDefinitionServiceImpl implements BpmProcessDefinitionServ
return new PageResult<>(BpmProcessDefinitionConvert.INSTANCE.convertList(processDefinitions, deploymentMap,
processDefinitionDOMap, formMap), definitionCount);
}
}

View File

@ -0,0 +1,87 @@
package cn.iocoder.yudao.module.bpm.service.definition;
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule.BpmTaskAssignRuleCreateReqVO;
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule.BpmTaskAssignRuleRespVO;
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule.BpmTaskAssignRuleUpdateReqVO;
import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmTaskAssignRuleDO;
import org.springframework.lang.Nullable;
import javax.validation.Valid;
import java.util.List;
/**
* BPM 任务分配规则 Service 接口
*
* @author 芋道源码
*/
public interface BpmTaskAssignRuleService {
/**
* 获得流程定义的任务分配规则数组
*
* @param processDefinitionId 流程定义的编号
* @param taskDefinitionKey 流程任务定义的 Key允许空
* @return 任务规则数组
*/
List<BpmTaskAssignRuleDO> getTaskAssignRuleListByProcessDefinitionId(String processDefinitionId,
@Nullable String taskDefinitionKey);
/**
* 获得流程模型的任务规则数组
*
* @param modelId 流程模型的编号
* @return 任务规则数组
*/
List<BpmTaskAssignRuleDO> getTaskAssignRuleListByModelId(String modelId);
/**
* 获得流程定义的任务分配规则数组
*
* @param modelId 流程模型的编号
* @param processDefinitionId 流程定义的编号
* @return 任务规则数组
*/
List<BpmTaskAssignRuleRespVO> getTaskAssignRuleList(String modelId, String processDefinitionId);
/**
* 创建任务分配规则
*
* @param reqVO 创建信息
* @return 规则编号
*/
Long createTaskAssignRule(@Valid BpmTaskAssignRuleCreateReqVO reqVO);
/**
* 更新任务分配规则
*
* @param reqVO 创建信息
*/
void updateTaskAssignRule(@Valid BpmTaskAssignRuleUpdateReqVO reqVO);
/**
* 判断指定流程模型和流程定义的分配规则是否相等
*
* @param modelId 流程模型编号
* @param processDefinitionId 流程定义编号
* @return 是否相等
*/
boolean isTaskAssignRulesEquals(String modelId, String processDefinitionId);
/**
* 将流程流程模型的任务分配规则复制一份给流程定义
* 目的每次流程模型部署时都会生成一个新的流程定义此时考虑到每次部署的流程不可变性所以需要复制一份给该流程定义
*
* @param fromModelId 流程模型编号
* @param toProcessDefinitionId 流程定义编号
*/
void copyTaskAssignRules(String fromModelId, String toProcessDefinitionId);
/**
* 校验流程模型的任务分配规则全部都配置了
* 目的如果有规则未配置会导致流程任务找不到负责人进而流程无法进行下去
*
* @param id 流程模型编号
*/
void checkTaskAssignRuleAllConfig(String id);
}

View File

@ -0,0 +1,76 @@
package cn.iocoder.yudao.module.bpm.service.task;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCreateReqVO;
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceMyPageReqVO;
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 org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.runtime.ProcessInstance;
import javax.validation.Valid;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* 流程实例 Service 接口
*
* @author 芋道源码
*/
public interface BpmProcessInstanceService {
/**
* 获得流程实例列表
*
* @param ids 流程实例的编号集合
* @return 流程实例列表
*/
List<ProcessInstance> getProcessInstances(Set<String> ids);
/**
* 获得流程实例 Map
*
* @param ids 流程实例的编号集合
* @return 流程实例列表 Map
*/
default Map<String, ProcessInstance> getProcessInstanceMap(Set<String> ids) {
return CollectionUtils.convertMap(getProcessInstances(ids), ProcessInstance::getProcessInstanceId);
}
/**
* 获得流程实例的分页
*
* @param userId 用户编号
* @param pageReqVO 分页请求
* @return 流程实例的分页
*/
PageResult<BpmProcessInstancePageItemRespVO> getMyProcessInstancePage(Long userId,
@Valid BpmProcessInstanceMyPageReqVO pageReqVO);
/**
* 创建流程实例提供给前端
*
* @param userId 用户编号
* @param createReqVO 创建信息
* @return 实例的编号
*/
String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqVO createReqVO);
/**
* 获得流程实例 VO 信息
*
* @param id 流程实例的编号
* @return 流程实例
*/
BpmProcessInstanceRespVO getProcessInstanceVO(String id);
/**
* 获得历史的流程实例
*
* @param id 流程实例的编号
* @return 历史的流程实例
*/
HistoricProcessInstance getHistoricProcessInstance(String id);
}

View File

@ -0,0 +1,167 @@
package cn.iocoder.yudao.module.bpm.service.task;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
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.instance.BpmProcessInstanceCreateReqVO;
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceMyPageReqVO;
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.convert.task.BpmProcessInstanceConvert;
import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionExtDO;
import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmProcessInstanceExtDO;
import cn.iocoder.yudao.module.bpm.dal.mysql.task.BpmProcessInstanceExtMapper;
import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService;
import cn.iocoder.yudao.module.system.api.dept.DeptApi;
import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.HistoryService;
import org.flowable.engine.RuntimeService;
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.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
import javax.validation.Valid;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.PROCESS_DEFINITION_IS_SUSPENDED;
import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.PROCESS_DEFINITION_NOT_EXISTS;
/**
* 流程实例 Service 实现类
*
* ProcessDefinition & ProcessInstance & Execution & Task 的关系
* 1. https://blog.csdn.net/bobozai86/article/details/105210414
*
* HistoricProcessInstance & ProcessInstance 的关系
* 1.https://my.oschina.net/843294669/blog/719024
* 简单来说前者 = 历史 + 运行中的流程实例后者仅是运行中的流程实例
*
* @author 芋道源码
*/
@Service
@Validated
@Slf4j
public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService {
@Resource
private RuntimeService runtimeService;
@Resource
private BpmProcessInstanceExtMapper processInstanceExtMapper;
@Resource
@Lazy // 解决循环依赖
private BpmTaskService taskService;
@Resource
private BpmProcessDefinitionService processDefinitionService;
@Resource
private HistoryService historyService;
@Resource
private AdminUserApi adminUserApi;
@Resource
private DeptApi deptApi;
@Override
public List<ProcessInstance> getProcessInstances(Set<String> ids) {
return runtimeService.createProcessInstanceQuery().processDefinitionIds(ids).list();
}
@Override
public PageResult<BpmProcessInstancePageItemRespVO> getMyProcessInstancePage(Long userId,
BpmProcessInstanceMyPageReqVO pageReqVO) {
// 通过 BpmProcessInstanceExtDO 先查询到对应的分页
PageResult<BpmProcessInstanceExtDO> pageResult = processInstanceExtMapper.selectPage(userId, pageReqVO);
if (CollUtil.isEmpty(pageResult.getList())) {
return new PageResult<>(pageResult.getTotal());
}
// 获得流程 Task Map
List<String> processInstanceIds = convertList(pageResult.getList(), BpmProcessInstanceExtDO::getProcessInstanceId);
Map<String, List<Task>> taskMap = taskService.getTaskMapByProcessInstanceIds(processInstanceIds);
// 转换返回
return BpmProcessInstanceConvert.INSTANCE.convertPage(pageResult, taskMap);
}
@Override
public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqVO createReqVO) {
// 获得流程定义
ProcessDefinition definition = processDefinitionService.getProcessDefinition(createReqVO.getProcessDefinitionId());
// 发起流程
return createProcessInstance0(userId, definition, createReqVO.getVariables(), null);
}
@Override
public BpmProcessInstanceRespVO getProcessInstanceVO(String id) {
// 获得流程实例
HistoricProcessInstance processInstance = getHistoricProcessInstance(id);
if (processInstance == null) {
return null;
}
BpmProcessInstanceExtDO processInstanceExt = processInstanceExtMapper.selectByProcessInstanceId(id);
Assert.notNull(processInstanceExt, "流程实例拓展({}) 不存在", id);
// 获得流程定义
ProcessDefinition processDefinition = processDefinitionService
.getProcessDefinition(processInstance.getProcessDefinitionId());
Assert.notNull(processDefinition, "流程定义({}) 不存在", processInstance.getProcessDefinitionId());
BpmProcessDefinitionExtDO processDefinitionExt = processDefinitionService.getProcessDefinitionExt(
processInstance.getProcessDefinitionId());
Assert.notNull(processDefinitionExt, "流程定义拓展({}) 不存在", id);
String bpmnXml = processDefinitionService.getProcessDefinitionBpmnXML(processInstance.getProcessDefinitionId());
// 获得 User
AdminUserRespDTO startUser = adminUserApi.getUser(NumberUtils.parseLong(processInstance.getStartUserId()));
DeptRespDTO dept = null;
if (startUser != null) {
dept = deptApi.getDept(startUser.getDeptId());
}
// 拼接结果
return BpmProcessInstanceConvert.INSTANCE.convert2(processInstance, processInstanceExt,
processDefinition, processDefinitionExt, bpmnXml, startUser, dept);
}
/**
* 获得历史的流程实例
*
* @param id 流程实例的编号
* @return 历史的流程实例
*/
@Override
public HistoricProcessInstance getHistoricProcessInstance(String id) {
return historyService.createHistoricProcessInstanceQuery().processInstanceId(id).singleResult();
}
private String createProcessInstance0(Long userId, ProcessDefinition definition,
Map<String, Object> variables, String businessKey) {
// 校验流程定义
if (definition == null) {
throw exception(PROCESS_DEFINITION_NOT_EXISTS);
}
if (definition.isSuspended()) {
throw exception(PROCESS_DEFINITION_IS_SUSPENDED);
}
// 创建流程实例
ProcessInstance instance = runtimeService.startProcessInstanceById(definition.getId(), businessKey, variables);
// 设置流程名字
runtimeService.setProcessInstanceName(instance.getId(), definition.getName());
// 补全流程实例的拓展表
processInstanceExtMapper.updateByProcessInstanceId(new BpmProcessInstanceExtDO().setProcessInstanceId(instance.getId())
.setFormVariables(variables));
return instance.getId();
}
}

View File

@ -0,0 +1,47 @@
package cn.iocoder.yudao.module.bpm.service.task;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskTodoPageItemRespVO;
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskTodoPageReqVO;
import org.flowable.task.api.Task;
import java.util.List;
import java.util.Map;
/**
* 流程任务实例 Service 接口
*
* @author jason
* @author 芋道源码
*/
public interface BpmTaskService {
/**
* 获得待办的流程任务分页
*
* @param userId 用户编号
* @param pageReqVO 分页请求
* @return 流程任务分页
*/
PageResult<BpmTaskTodoPageItemRespVO> getTodoTaskPage(Long userId, BpmTaskTodoPageReqVO pageReqVO);
/**
* 获得流程任务 Map
*
* @param processInstanceIds 流程实例的编号数组
* @return 流程任务 Map
*/
default Map<String, List<Task>> getTaskMapByProcessInstanceIds(List<String> processInstanceIds) {
return CollectionUtils.convertMultiMap(getTasksByProcessInstanceIds(processInstanceIds),
Task::getProcessInstanceId);
}
/**
* 获得流程任务列表
*
* @param processInstanceIds 流程实例的编号数组
* @return 流程任务列表
*/
List<Task> getTasksByProcessInstanceIds(List<String> processInstanceIds);
}

View File

@ -0,0 +1,82 @@
package cn.iocoder.yudao.module.bpm.service.task;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.PageUtils;
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskTodoPageItemRespVO;
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskTodoPageReqVO;
import cn.iocoder.yudao.module.bpm.convert.task.BpmTaskConvert;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.TaskService;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.task.api.Task;
import org.flowable.task.api.TaskQuery;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
/**
* 流程任务实例 Service 实现类
*
* @author jason
* @author 芋道源码
*/
@Slf4j
@Service
public class BpmTaskServiceImpl implements BpmTaskService{
@Resource
private TaskService taskService;
@Resource
private AdminUserApi adminUserApi;
@Resource
private BpmProcessInstanceService processInstanceService;
@Override
public PageResult<BpmTaskTodoPageItemRespVO> getTodoTaskPage(Long userId, BpmTaskTodoPageReqVO pageVO) {
// 查询待办任务
TaskQuery taskQuery = taskService.createTaskQuery()
.taskAssignee(String.valueOf(userId)) // 分配给自己
.orderByTaskCreateTime().desc(); // 创建时间倒序
if (StrUtil.isNotBlank(pageVO.getName())) {
taskQuery.taskNameLike("%" + pageVO.getName() + "%");
}
if (pageVO.getBeginCreateTime() != null) {
taskQuery.taskCreatedAfter(pageVO.getBeginCreateTime());
}
if (pageVO.getEndCreateTime() != null) {
taskQuery.taskCreatedBefore(pageVO.getEndCreateTime());
}
// 执行查询
List<Task> tasks = taskQuery.listPage(PageUtils.getStart(pageVO), pageVO.getPageSize());
if (CollUtil.isEmpty(tasks)) {
return PageResult.empty(taskQuery.count());
}
// 获得 ProcessInstance Map
Map<String, ProcessInstance> processInstanceMap = processInstanceService.getProcessInstanceMap(
convertSet(tasks, Task::getProcessInstanceId));
// 获得 User Map
Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(
convertSet(processInstanceMap.values(), instance -> Long.valueOf(instance.getStartUserId())));
// 拼接结果
return new PageResult<>(BpmTaskConvert.INSTANCE.convertList1(tasks, processInstanceMap, userMap),
taskQuery.count());
}
@Override
public List<Task> getTasksByProcessInstanceIds(List<String> processInstanceIds) {
if (CollUtil.isEmpty(processInstanceIds)) {
return Collections.emptyList();
}
return taskService.createTaskQuery().processInstanceIdIn(processInstanceIds).list();
}
}