package com.ycl.service.impl; import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSONObject; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper; import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper; import com.ycl.common.constant.ProcessConstants; import com.ycl.common.core.domain.AjaxResult; import com.ycl.common.core.domain.entity.SysRole; import com.ycl.common.core.domain.entity.SysUser; import com.ycl.common.enums.FlowComment; import com.ycl.common.utils.SecurityUtils; import com.ycl.domain.dto.FlowTaskDto; import com.ycl.domain.entity.ProjectInfo; import com.ycl.domain.entity.ProjectProcess; import com.ycl.domain.vo.ProjectProcessDetailVO; import com.ycl.mapper.ProjectInfoMapper; import com.ycl.mapper.ProjectProcessMapper; import com.ycl.service.ProjectProcessService; import com.ycl.common.base.Result; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.ycl.domain.form.ProjectProcessForm; import com.ycl.domain.vo.ProjectProcessVO; import com.ycl.domain.query.ProjectProcessQuery; import com.ycl.system.service.ISysRoleService; import com.ycl.system.service.ISysUserService; import org.apache.commons.lang3.StringUtils; import org.flowable.bpmn.model.BpmnModel; import org.flowable.bpmn.model.FlowElement; import org.flowable.bpmn.model.Process; import org.flowable.bpmn.model.StartEvent; import org.flowable.engine.*; import org.flowable.engine.history.HistoricProcessInstance; import org.flowable.engine.repository.ProcessDefinition; import org.flowable.engine.runtime.ProcessInstance; import org.flowable.identitylink.api.IdentityLink; import org.flowable.task.api.Task; import org.flowable.task.api.TaskQuery; import org.flowable.task.api.history.HistoricTaskInstance; import org.flowable.task.api.history.HistoricTaskInstanceQuery; import org.springframework.stereotype.Service; import lombok.RequiredArgsConstructor; import com.ycl.framework.utils.PageUtil; import org.springframework.beans.BeanUtils; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.Assert; import java.util.*; import java.util.stream.Collectors; /** * 项目流程关系表 服务实现类 * * @author xp * @since 2024-11-26 */ @Service @RequiredArgsConstructor public class ProjectProcessServiceImpl extends ServiceImpl implements ProjectProcessService { private final ProjectProcessMapper projectProcessMapper; private final RuntimeService runtimeService; private final TaskService taskService; private final IdentityService identityService; private final RepositoryService repositoryService; private final ProjectInfoMapper projectInfoMapper; private final HistoryService historyService; private final ISysUserService sysUserService; private final ISysRoleService sysRoleService; /** * 分页查询 * @param query * @return */ @Override public Result page(ProjectProcessQuery query) { IPage page = PageUtil.getPage(query, ProjectProcessVO.class); baseMapper.getPage(page, query); return Result.ok().data(page.getRecords()).total(page.getTotal()); } /** * 获取流程详情 * @param projectId * @return */ @Override public Result detail(Long projectId, String processId) { // 项目信息 ProjectInfo projectInfo = new LambdaQueryChainWrapper<>(projectInfoMapper) .select(ProjectInfo::getId, ProjectInfo::getProjectName, ProjectInfo::getProjectCode) .eq(ProjectInfo::getId, projectId) .one(); if (Objects.isNull(projectInfo)) { return Result.error("该项目不存在"); } ProjectProcess projectProcess = new LambdaQueryChainWrapper<>(baseMapper) .eq(ProjectProcess::getProjectId, projectId) .eq(ProjectProcess::getFlowableProcessId, processId) .one(); if (Objects.isNull(projectProcess)) { return Result.error("该项目未设置流程"); } ProjectProcessDetailVO detail = new ProjectProcessDetailVO(); detail.setProjectId(projectId); detail.setProjectName(projectInfo.getProjectName()); detail.setProjectCode(projectInfo.getProjectCode()); ProjectProcessDetailVO.TaskStatistics taskStatistics = new ProjectProcessDetailVO.TaskStatistics(); // 状态统计 taskStatistics.setTotalTaskNum(this.getTotalTaskNum(processId)); taskStatistics.setTodoTaskNum(this.getTodoTaskNum(projectProcess.getProcessInstanceId())); // taskStatistics.setCurrentTask(this.getCurrentNodeTaskList(projectProcess.getProcessInstanceId())); taskStatistics.setRemainingTaskNum(this.getNotFinishedTaskNum(projectProcess.getProcessInstanceId())); detail.setStatistics(taskStatistics); Result result = Result.ok(); // 代办任务 this.getTodoTaskList(projectProcess.getProcessInstanceId(),"", 1, 5, result); return result.data(detail); } @Override public Result projectSetProcess(ProjectProcessForm form) { // 查询该项目是否已经绑定过流程了,检查绑定的流程是否在运行,在运行就删了 ProjectProcess pp = new LambdaQueryChainWrapper<>(baseMapper) .eq(ProjectProcess::getProjectId, form.getProjectId()) .one(); if (Objects.nonNull(pp)) { // TODO 处理之前绑定过的流程数据 new LambdaUpdateChainWrapper<>(baseMapper) .eq(ProjectProcess::getProjectId, form.getProjectId()) .set(ProjectProcess::getFlowableProcessId, form.getFlowableProcessId()) .update(); } else { ProjectProcess entity = ProjectProcessForm.getEntityByForm(form, null); baseMapper.insert(entity); } return Result.ok("流程变更成功"); } @Override @Transactional(rollbackFor = Exception.class) public Result startProcess(String projectId, String processId) { ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(processId) .latestVersion().singleResult(); if (Objects.nonNull(processDefinition) && processDefinition.isSuspended()) { return Result.error("该流程已被挂起,请先激活流程"); } Map variables = new HashMap<>(2); // 设置流程发起人Id到流程中 SysUser sysUser = SecurityUtils.getLoginUser().getUser(); identityService.setAuthenticatedUserId(sysUser.getUserId().toString()); variables.put(ProcessConstants.PROCESS_INITIATOR, sysUser.getUserId()); ProcessInstance processInstance = runtimeService.startProcessInstanceById(processId, projectId, variables); // // 流程发起时 跳过发起人节点 // // 给第一步申请人节点设置任务执行人和意见 // Task task = taskService.createTaskQuery().processInstanceId(processInstance.getProcessInstanceId()).singleResult(); // if (Objects.nonNull(task)) { // taskService.addComment(task.getId(), processInstance.getProcessInstanceId(), FlowComment.NORMAL.getType(), sysUser.getNickName() + "发起流程申请"); // taskService.complete(task.getId(), variables); // } // 项目流程关联流程实例id new LambdaUpdateChainWrapper<>(baseMapper) .eq(ProjectProcess::getProjectId, projectId) .eq(ProjectProcess::getFlowableProcessId, processId) .set(ProjectProcess::getProcessInstanceId, processInstance.getProcessInstanceId()) .update(); return Result.ok("流程启动成功"); } private void getTodoTaskList(String processInstanceId, String name, Integer pageNum, Integer pageSize, Result result) { TaskQuery taskQuery = taskService.createTaskQuery() .active() .processInstanceId(processInstanceId) .includeProcessVariables() .orderByTaskCreateTime().desc(); // TODO 传入名称查询不到数据? if (StringUtils.isNotBlank(name)) { taskQuery.processDefinitionNameLike(name); } result.total(taskQuery.count()); List taskList = taskQuery.listPage(pageSize * (pageNum - 1), pageSize); List flowList = new ArrayList<>(); for (Task task : taskList) { FlowTaskDto flowTask = new FlowTaskDto(); // 当前流程信息 flowTask.setTaskId(task.getId()); flowTask.setTaskDefKey(task.getTaskDefinitionKey()); flowTask.setCreateTime(task.getCreateTime()); flowTask.setProcDefId(task.getProcessDefinitionId()); flowTask.setExecutionId(task.getExecutionId()); flowTask.setTaskName(task.getName()); // 流程定义信息 ProcessDefinition pd = repositoryService.createProcessDefinitionQuery() .processDefinitionId(task.getProcessDefinitionId()) .singleResult(); flowTask.setDeployId(pd.getDeploymentId()); flowTask.setProcDefName(pd.getName()); flowTask.setProcDefVersion(pd.getVersion()); flowTask.setProcInsId(task.getProcessInstanceId()); // 流程发起人信息 HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery() .processInstanceId(task.getProcessInstanceId()) .singleResult(); SysUser startUser = sysUserService.selectUserById(Long.parseLong(historicProcessInstance.getStartUserId())); flowTask.setStartUserId(startUser.getUserId().toString()); flowTask.setStartUserName(startUser.getNickName()); flowTask.setStartDeptName(Objects.nonNull(startUser.getDept()) ? startUser.getDept().getDeptName() : ""); // 流程处理人信息 List identityLinksForTask = taskService.getIdentityLinksForTask(task.getId()); for (IdentityLink identityLink : identityLinksForTask) { // 绑定的是用户,查出用户姓名、部门 if (StringUtils.isNotBlank(identityLink.getUserId())) { SysUser sysUser = sysUserService.selectUserById(Long.parseLong(identityLink.getUserId())); if (Objects.nonNull(sysUser)) { flowTask.setAssigneeId(sysUser.getUserId()); if (Objects.nonNull(sysUser.getDept())) { flowTask.setAssigneeDeptName(sysUser.getDept().getDeptName()); } flowTask.setAssigneeName(sysUser.getNickName()); } // 绑定的是角色,查出角色名称 } else if (StringUtils.isNotBlank(identityLink.getGroupId())) { SysRole role = sysRoleService.selectRoleById(Long.parseLong(identityLink.getGroupId())); if (Objects.nonNull(role)) { flowTask.setAssigneeId(Long.parseLong(identityLink.getGroupId())); flowTask.setAssigneeDeptName("由拥有角色:【" + role.getRoleName() + "】的人处理"); flowTask.setAssigneeName("暂未处理"); } } } flowList.add(flowTask); } result.put("taskList", flowList); } /** * 获取流程节点数(总任务数,不包含开始、结束等特殊的,只统计UserTask类型的) * * @param processDefinitionId 流程定义id * @return */ private Long getTotalTaskNum(String processDefinitionId) { // 获取流程定义 ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery() .processDefinitionId(processDefinitionId) .singleResult(); if (processDefinition == null) { throw new IllegalArgumentException("流程定义ID无效: " + processDefinitionId); } // 获取BPMN模型 BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId); if (bpmnModel == null) { throw new IllegalStateException("无法获取BPMN模型: " + processDefinitionId); } // 获取流程对象 Process process = bpmnModel.getProcessById(processDefinition.getKey()); if (process == null) { throw new IllegalStateException("无法获取流程对象: " + processDefinition.getKey()); } // 计算任务节点数量 Long taskNodeCount = 0L; List flowElements = process.getFlowElements().stream().toList(); for (FlowElement flowElement : flowElements) { if (flowElement instanceof org.flowable.bpmn.model.UserTask) { taskNodeCount++; } } return taskNodeCount; } /** * 获取流程剩余未完成的任务数 * * @param processInstanceId * @return */ private Long getNotFinishedTaskNum(String processInstanceId) { return historyService.createHistoricTaskInstanceQuery().processInstanceId(processInstanceId).processUnfinished().count(); } /** * 获取待办任务数 * * @param processInstanceId * @return */ private Long getTodoTaskNum(String processInstanceId) { return taskService.createTaskQuery().active().processInstanceId(processInstanceId).count(); } /** * 获取当前环节的所有任务数 * * @param processInstanceId * @return */ private List getCurrentNodeTaskList(String processInstanceId) { return taskService.createTaskQuery().processDefinitionId(processInstanceId).list(); } }