三期内容优化
This commit is contained in:
@@ -0,0 +1,14 @@
|
||||
package com.ruoyi.workflow.domain;
|
||||
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@Data
|
||||
public class FlowRecord {
|
||||
|
||||
private Date startTime;
|
||||
private Date endTime;
|
||||
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.ruoyi.workflow.service;
|
||||
|
||||
import com.ruoyi.workflow.domain.FlowRecord;
|
||||
import com.ruoyi.workflow.domain.bo.WfTaskBo;
|
||||
import org.flowable.bpmn.model.FlowElement;
|
||||
import org.flowable.engine.runtime.ProcessInstance;
|
||||
@@ -114,4 +115,6 @@ public interface IWfTaskService {
|
||||
* @param variables 流程参数
|
||||
*/
|
||||
void startFirstTask(ProcessInstance processInstance, Map<String, Object> variables);
|
||||
|
||||
public List<FlowRecord> getApprovedRecords(Long userId, String category);
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ import com.ruoyi.flowable.flow.CustomProcessDiagramGenerator;
|
||||
import com.ruoyi.flowable.flow.FlowableUtils;
|
||||
import com.ruoyi.flowable.utils.ModelUtils;
|
||||
import com.ruoyi.flowable.utils.TaskUtils;
|
||||
import com.ruoyi.workflow.domain.FlowRecord;
|
||||
import com.ruoyi.workflow.domain.bo.WfTaskBo;
|
||||
import com.ruoyi.workflow.service.IWfCopyService;
|
||||
import com.ruoyi.workflow.service.IWfTaskService;
|
||||
@@ -39,10 +40,12 @@ import org.flowable.image.ProcessDiagramGenerator;
|
||||
import org.flowable.task.api.DelegationState;
|
||||
import org.flowable.task.api.Task;
|
||||
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.io.InputStream;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@@ -119,15 +122,15 @@ public class WfTaskServiceImpl extends FlowServiceFactory implements IWfTaskServ
|
||||
}
|
||||
// 获取流程实例
|
||||
ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
|
||||
.processInstanceId(taskBo.getProcInsId())
|
||||
.singleResult();
|
||||
.processInstanceId(taskBo.getProcInsId())
|
||||
.singleResult();
|
||||
if (processInstance == null) {
|
||||
throw new RuntimeException("流程实例不存在,请确认!");
|
||||
}
|
||||
// 获取流程定义信息
|
||||
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
|
||||
.processDefinitionId(task.getProcessDefinitionId())
|
||||
.singleResult();
|
||||
.processDefinitionId(task.getProcessDefinitionId())
|
||||
.singleResult();
|
||||
|
||||
identityService.setAuthenticatedUserId(TaskUtils.getUserId());
|
||||
// 添加审批意见
|
||||
@@ -141,9 +144,9 @@ public class WfTaskServiceImpl extends FlowServiceFactory implements IWfTaskServ
|
||||
List<Execution> executions = runtimeService.createExecutionQuery().parentId(task.getProcessInstanceId()).list();
|
||||
List<String> executionIds = executions.stream().map(Execution::getId).collect(Collectors.toList());
|
||||
runtimeService.createChangeActivityStateBuilder()
|
||||
.processInstanceId(task.getProcessInstanceId())
|
||||
.moveExecutionsToSingleActivityId(executionIds, endEvent.getId())
|
||||
.changeState();
|
||||
.processInstanceId(task.getProcessInstanceId())
|
||||
.moveExecutionsToSingleActivityId(executionIds, endEvent.getId())
|
||||
.changeState();
|
||||
// 处理抄送用户
|
||||
if (!copyService.makeCopy(taskBo)) {
|
||||
throw new RuntimeException("抄送任务失败");
|
||||
@@ -206,8 +209,8 @@ public class WfTaskServiceImpl extends FlowServiceFactory implements IWfTaskServ
|
||||
try {
|
||||
// 1 对 1 或 多 对 1 情况,currentIds 当前要跳转的节点列表(1或多),targetKey 跳转到的节点(1)
|
||||
runtimeService.createChangeActivityStateBuilder()
|
||||
.processInstanceId(task.getProcessInstanceId())
|
||||
.moveActivityIdsToSingleActivityId(currentIds, bo.getTargetKey()).changeState();
|
||||
.processInstanceId(task.getProcessInstanceId())
|
||||
.moveActivityIdsToSingleActivityId(currentIds, bo.getTargetKey()).changeState();
|
||||
} catch (FlowableObjectNotFoundException e) {
|
||||
throw new RuntimeException("未找到流程实例,流程可能已发生变化");
|
||||
} catch (FlowableException e) {
|
||||
@@ -238,16 +241,16 @@ public class WfTaskServiceImpl extends FlowServiceFactory implements IWfTaskServ
|
||||
BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinition.getId());
|
||||
// 查询历史节点实例
|
||||
List<HistoricActivityInstance> activityInstanceList = historyService.createHistoricActivityInstanceQuery()
|
||||
.processInstanceId(task.getProcessInstanceId())
|
||||
.activityType(BpmnXMLConstants.ELEMENT_TASK_USER)
|
||||
.finished()
|
||||
.orderByHistoricActivityInstanceEndTime().asc()
|
||||
.list();
|
||||
.processInstanceId(task.getProcessInstanceId())
|
||||
.activityType(BpmnXMLConstants.ELEMENT_TASK_USER)
|
||||
.finished()
|
||||
.orderByHistoricActivityInstanceEndTime().asc()
|
||||
.list();
|
||||
List<String> activityIdList = activityInstanceList.stream()
|
||||
.map(HistoricActivityInstance::getActivityId)
|
||||
.filter(activityId -> !StringUtils.equals(activityId, task.getTaskDefinitionKey()))
|
||||
.distinct()
|
||||
.collect(Collectors.toList());
|
||||
.map(HistoricActivityInstance::getActivityId)
|
||||
.filter(activityId -> !StringUtils.equals(activityId, task.getTaskDefinitionKey()))
|
||||
.distinct()
|
||||
.collect(Collectors.toList());
|
||||
// 获取当前任务节点元素
|
||||
FlowElement source = ModelUtils.getFlowElementById(bpmnModel, task.getTaskDefinitionKey());
|
||||
List<FlowElement> elementList = new ArrayList<>();
|
||||
@@ -313,7 +316,7 @@ public class WfTaskServiceImpl extends FlowServiceFactory implements IWfTaskServ
|
||||
throw new ServiceException("获取任务失败!");
|
||||
}
|
||||
StringBuilder commentBuilder = new StringBuilder(LoginHelper.getNickName())
|
||||
.append("->");
|
||||
.append("->");
|
||||
String nickName = sysUserService.selectNickNameById(Long.parseLong(bo.getUserId()));
|
||||
if (StringUtils.isNotBlank(nickName)) {
|
||||
commentBuilder.append(nickName);
|
||||
@@ -353,7 +356,7 @@ public class WfTaskServiceImpl extends FlowServiceFactory implements IWfTaskServ
|
||||
throw new ServiceException("获取任务失败!");
|
||||
}
|
||||
StringBuilder commentBuilder = new StringBuilder(LoginHelper.getNickName())
|
||||
.append("->");
|
||||
.append("->");
|
||||
String nickName = sysUserService.selectNickNameById(Long.parseLong(bo.getUserId()));
|
||||
if (StringUtils.isNotBlank(nickName)) {
|
||||
commentBuilder.append(nickName);
|
||||
@@ -392,7 +395,7 @@ public class WfTaskServiceImpl extends FlowServiceFactory implements IWfTaskServ
|
||||
}
|
||||
|
||||
ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
|
||||
.processInstanceId(bo.getProcInsId()).singleResult();
|
||||
.processInstanceId(bo.getProcInsId()).singleResult();
|
||||
BpmnModel bpmnModel = repositoryService.getBpmnModel(processInstance.getProcessDefinitionId());
|
||||
if (Objects.nonNull(bpmnModel)) {
|
||||
Process process = bpmnModel.getMainProcess();
|
||||
@@ -404,12 +407,12 @@ public class WfTaskServiceImpl extends FlowServiceFactory implements IWfTaskServ
|
||||
// 获取当前流程最后一个节点
|
||||
String endId = endNodes.get(0).getId();
|
||||
List<Execution> executions = runtimeService.createExecutionQuery()
|
||||
.parentId(processInstance.getProcessInstanceId()).list();
|
||||
.parentId(processInstance.getProcessInstanceId()).list();
|
||||
List<String> executionIds = new ArrayList<>();
|
||||
executions.forEach(execution -> executionIds.add(execution.getId()));
|
||||
// 变更流程为已结束状态
|
||||
runtimeService.createChangeActivityStateBuilder()
|
||||
.moveExecutionsToSingleActivityId(executionIds, endId).changeState();
|
||||
.moveExecutionsToSingleActivityId(executionIds, endId).changeState();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -426,17 +429,17 @@ public class WfTaskServiceImpl extends FlowServiceFactory implements IWfTaskServ
|
||||
String taskId = taskBo.getTaskId();
|
||||
// 校验流程是否结束
|
||||
ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
|
||||
.processInstanceId(procInsId)
|
||||
.active()
|
||||
.singleResult();
|
||||
if(ObjectUtil.isNull(processInstance)) {
|
||||
.processInstanceId(procInsId)
|
||||
.active()
|
||||
.singleResult();
|
||||
if (ObjectUtil.isNull(processInstance)) {
|
||||
throw new RuntimeException("流程已结束或已挂起,无法执行撤回操作");
|
||||
}
|
||||
// 获取待撤回任务实例
|
||||
HistoricTaskInstance currTaskIns = historyService.createHistoricTaskInstanceQuery()
|
||||
.taskId(taskId)
|
||||
.taskAssignee(TaskUtils.getUserId())
|
||||
.singleResult();
|
||||
.taskId(taskId)
|
||||
.taskAssignee(TaskUtils.getUserId())
|
||||
.singleResult();
|
||||
if (ObjectUtil.isNull(currTaskIns)) {
|
||||
throw new RuntimeException("当前任务不存在,无法执行撤回操作");
|
||||
}
|
||||
@@ -449,10 +452,10 @@ public class WfTaskServiceImpl extends FlowServiceFactory implements IWfTaskServ
|
||||
|
||||
// 获取当前节点之后已完成的流程历史节点
|
||||
List<HistoricTaskInstance> finishedTaskInsList = historyService.createHistoricTaskInstanceQuery()
|
||||
.processInstanceId(procInsId)
|
||||
.taskCreatedAfter(currTaskIns.getEndTime())
|
||||
.finished()
|
||||
.list();
|
||||
.processInstanceId(procInsId)
|
||||
.taskCreatedAfter(currTaskIns.getEndTime())
|
||||
.finished()
|
||||
.list();
|
||||
for (HistoricTaskInstance finishedTaskInstance : finishedTaskInsList) {
|
||||
// 检查已完成流程历史节点是否存在下一级中
|
||||
if (CollUtil.contains(nextUserTaskKeys, finishedTaskInstance.getTaskDefinitionKey())) {
|
||||
@@ -474,8 +477,8 @@ public class WfTaskServiceImpl extends FlowServiceFactory implements IWfTaskServ
|
||||
}
|
||||
try {
|
||||
runtimeService.createChangeActivityStateBuilder()
|
||||
.processInstanceId(procInsId)
|
||||
.moveExecutionsToSingleActivityId(revokeExecutionIds, currTaskIns.getTaskDefinitionKey()).changeState();
|
||||
.processInstanceId(procInsId)
|
||||
.moveExecutionsToSingleActivityId(revokeExecutionIds, currTaskIns.getTaskDefinitionKey()).changeState();
|
||||
} catch (FlowableObjectNotFoundException e) {
|
||||
throw new RuntimeException("未找到流程实例,流程可能已发生变化");
|
||||
} catch (FlowableException e) {
|
||||
@@ -507,7 +510,7 @@ public class WfTaskServiceImpl extends FlowServiceFactory implements IWfTaskServ
|
||||
|
||||
// 获得活动的节点
|
||||
List<HistoricActivityInstance> highLightedFlowList = historyService.createHistoricActivityInstanceQuery()
|
||||
.processInstanceId(processId).orderByHistoricActivityInstanceStartTime().asc().list();
|
||||
.processInstanceId(processId).orderByHistoricActivityInstanceStartTime().asc().list();
|
||||
|
||||
List<String> highLightedFlows = new ArrayList<>();
|
||||
List<String> highLightedNodes = new ArrayList<>();
|
||||
@@ -528,7 +531,7 @@ public class WfTaskServiceImpl extends FlowServiceFactory implements IWfTaskServ
|
||||
//获取自定义图片生成器
|
||||
ProcessDiagramGenerator diagramGenerator = new CustomProcessDiagramGenerator();
|
||||
return diagramGenerator.generateDiagram(bpmnModel, "png", highLightedNodes, highLightedFlows, configuration.getActivityFontName(),
|
||||
configuration.getLabelFontName(), configuration.getAnnotationFontName(), configuration.getClassLoader(), 1.0, true);
|
||||
configuration.getLabelFontName(), configuration.getAnnotationFontName(), configuration.getClassLoader(), 1.0, true);
|
||||
|
||||
}
|
||||
|
||||
@@ -541,10 +544,10 @@ public class WfTaskServiceImpl extends FlowServiceFactory implements IWfTaskServ
|
||||
@Override
|
||||
public Map<String, Object> getProcessVariables(String taskId) {
|
||||
HistoricTaskInstance historicTaskInstance = historyService.createHistoricTaskInstanceQuery()
|
||||
.includeProcessVariables()
|
||||
.finished()
|
||||
.taskId(taskId)
|
||||
.singleResult();
|
||||
.includeProcessVariables()
|
||||
.finished()
|
||||
.taskId(taskId)
|
||||
.singleResult();
|
||||
if (Objects.nonNull(historicTaskInstance)) {
|
||||
return historicTaskInstance.getProcessVariables();
|
||||
}
|
||||
@@ -553,8 +556,9 @@ public class WfTaskServiceImpl extends FlowServiceFactory implements IWfTaskServ
|
||||
|
||||
/**
|
||||
* 启动第一个任务
|
||||
*
|
||||
* @param processInstance 流程实例
|
||||
* @param variables 流程参数
|
||||
* @param variables 流程参数
|
||||
*/
|
||||
@Override
|
||||
public void startFirstTask(ProcessInstance processInstance, Map<String, Object> variables) {
|
||||
@@ -574,15 +578,16 @@ public class WfTaskServiceImpl extends FlowServiceFactory implements IWfTaskServ
|
||||
|
||||
/**
|
||||
* 指派下一任务审批人
|
||||
* @param bpmnModel bpmn模型
|
||||
*
|
||||
* @param bpmnModel bpmn模型
|
||||
* @param processInsId 流程实例id
|
||||
* @param userIds 用户ids
|
||||
* @param userIds 用户ids
|
||||
*/
|
||||
private void assignNextUsers(BpmnModel bpmnModel, String processInsId, String userIds) {
|
||||
// 获取所有节点信息
|
||||
List<Task> list = taskService.createTaskQuery()
|
||||
.processInstanceId(processInsId)
|
||||
.list();
|
||||
.processInstanceId(processInsId)
|
||||
.list();
|
||||
if (list.size() == 0) {
|
||||
return;
|
||||
}
|
||||
@@ -620,4 +625,107 @@ public class WfTaskServiceImpl extends FlowServiceFactory implements IWfTaskServ
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 根据 category + userId 查询已审批通过(流程已结束)的记录,提取 startTime, endTime 返回
|
||||
*
|
||||
* @param userId 当前用户ID
|
||||
* @param category 流程分类 (如 "trip" 出差, "absence" 请假)
|
||||
* @return 已审批通过的记录列表,每个包含 startTime, endTime
|
||||
*/
|
||||
@Override
|
||||
public List<FlowRecord> getApprovedRecords(Long userId, String category) {
|
||||
List<FlowRecord> result = new ArrayList<>();
|
||||
|
||||
// 1) 先查找所有 与 category 匹配的流程定义(可能有多个版本)
|
||||
List<ProcessDefinition> definitions = repositoryService.createProcessDefinitionQuery()
|
||||
.processDefinitionCategory(category)
|
||||
.latestVersion() // 如果只想用最新版本,可加这一行
|
||||
.list();
|
||||
|
||||
if (definitions == null || definitions.isEmpty()) {
|
||||
return result; // 没找到对应分类的流程定义,直接返回空
|
||||
}
|
||||
|
||||
// 收集所有流程定义ID
|
||||
List<String> defIds = definitions.stream()
|
||||
.map(ProcessDefinition::getId)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
// 2) 根据流程定义ID列表 + startedBy(userId) + 已结束流程,查流程实例
|
||||
for (String defId : defIds) {
|
||||
List<HistoricProcessInstance> hpiList = historyService.createHistoricProcessInstanceQuery()
|
||||
.processDefinitionId(defId)
|
||||
.startedBy(String.valueOf(userId))
|
||||
.finished() // 已审批完成 / 已结束
|
||||
.list();
|
||||
// 3)对每个已结束的流程实例,去找 startTime, endTime 变量
|
||||
for (HistoricProcessInstance hpi : hpiList) {
|
||||
String procInstId = hpi.getId();
|
||||
// 3.1) 如果 startTime, endTime 是存流程变量,直接查 HistoricVariableInstance
|
||||
List<HistoricVariableInstance> varList = historyService.createHistoricVariableInstanceQuery()
|
||||
.processInstanceId(procInstId)
|
||||
.list();
|
||||
|
||||
// 根据你的实际变量名提取
|
||||
Date startDate = null;
|
||||
Date endDate = null;
|
||||
for (HistoricVariableInstance var : varList) {
|
||||
if ("startTime".equals(var.getVariableName())) {
|
||||
// 若你的流程里存的就是 Date 类型,可以直接转
|
||||
startDate = (Date) var.getValue();
|
||||
} else if ("endTime".equals(var.getVariableName())) {
|
||||
endDate = (Date) var.getValue();
|
||||
}
|
||||
}
|
||||
|
||||
// 3.2) 或者,如果 startTime, endTime 是 FormProperty,则可用 HistoricDetailQuery
|
||||
// 下面演示如果在表单属性里
|
||||
// (示例仅供参考,实际要看你在模型里是否使用了 <formProperty/> )
|
||||
/*
|
||||
List<HistoricDetail> details = historyService.createHistoricDetailQuery()
|
||||
.processInstanceId(procInstId)
|
||||
.formProperties()
|
||||
.list();
|
||||
for (HistoricDetail d : details) {
|
||||
HistoricFormProperty fp = (HistoricFormProperty) d;
|
||||
if ("startTime".equals(fp.getPropertyId())) {
|
||||
// 这里可能需要 parse 成 Date
|
||||
startDate = parseDate(fp.getPropertyValue());
|
||||
} else if ("endTime".equals(fp.getPropertyId())) {
|
||||
endDate = parseDate(fp.getPropertyValue());
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// 4) 最后封装到 FlowRecord
|
||||
if (startDate != null && endDate != null) {
|
||||
FlowRecord record = new FlowRecord();
|
||||
record.setStartTime(startDate);
|
||||
record.setEndTime(endDate);
|
||||
// 你还可以记录更多字段,如: record.setCategory(category);
|
||||
result.add(record);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 如果需要解析字符串 => Date,可以用 SimpleDateFormat 或其他方式
|
||||
*/
|
||||
private Date parseDate(String dateStr) {
|
||||
if (dateStr == null) return null;
|
||||
try {
|
||||
return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(dateStr);
|
||||
} catch (Exception e) {
|
||||
// 失败再试别的格式
|
||||
try {
|
||||
return new SimpleDateFormat("yyyy-MM-dd").parse(dateStr);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user