工作流Flowable实战 (四)查看流程图


一、流程图

在这里插入图片描述
比较简单,直接上代码

@GetMapping("resource-view")
public void resourceView(@RequestParam String processDefinitionId, String processInstanceId, HttpServletResponse response) throws Exception {
	// 获取流程图
	BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
	ProcessEngineConfiguration engConf = processEngine.getProcessEngineConfiguration();

	ProcessDiagramGenerator diagramGenerator = new CustomProcessDiagramGenerator();
	InputStream in = diagramGenerator.generateDiagram(bpmnModel, "bmp", Collections.EMPTY_LIST, Collections.EMPTY_LIST, engConf.getActivityFontName(),
		engConf.getLabelFontName(), engConf.getAnnotationFontName(), engConf.getClassLoader(), 1.0, true);
	OutputStream out = null;
	byte[] buf = new byte[1024];
	int length;
	try {
		out = response.getOutputStream();
		while ((length = in.read(buf)) != -1) {
			out.write(buf, 0, length);
		}
	} catch (IOException e) {
		log.error("操作异常", e);
	} finally {
		IoUtil.closeSilently(out);
		IoUtil.closeSilently(in);
	}
}

二、流程跟踪

在这里插入图片描述
在这里插入图片描述
流程跟踪相对复杂一些,需要高亮显示流程已经经过的节点,将当前节点标识为绿色,并且鼠标移至节点上要显示节点信息,我们先看生成高亮流程图。

1、高亮流程图

@GetMapping(value = "diagram-view")
public void diagramView(String processInstanceId, HttpServletResponse httpServletResponse) {
	// 获得当前活动的节点
	String processDefinitionId;
	// 如果流程已经结束,则得到结束节点
	if (this.isFinished(processInstanceId)) {
		HistoricProcessInstance pi = historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
		processDefinitionId = pi.getProcessDefinitionId();
	} else {
		// 如果流程没有结束,则取当前活动节点
		// 根据流程实例ID获得当前处于活动状态的ActivityId合集
		ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
		processDefinitionId = pi.getProcessDefinitionId();
	}
	List<String> highLightedActivities = new ArrayList<>();

	// 获得活动的节点
	List<HistoricActivityInstance> highLightedActivityList = historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId).orderByHistoricActivityInstanceStartTime().asc().list();
	List<String> highLightedFlows = new ArrayList<>();

	for (HistoricActivityInstance tempActivity : highLightedActivityList) {
		String activityId = tempActivity.getActivityId();
		highLightedActivities.add(activityId);
		if("sequenceFlow".equals(tempActivity.getActivityType())){
			highLightedFlows.add(tempActivity.getActivityId());
		}
	}

	// 获取流程图
	BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
	ProcessEngineConfiguration engConf = processEngine.getProcessEngineConfiguration();

	ProcessDiagramGenerator diagramGenerator = engConf.getProcessDiagramGenerator();
//		ProcessDiagramGenerator diagramGenerator = new CustomProcessDiagramGenerator();
	InputStream in = diagramGenerator.generateDiagram(bpmnModel, "bmp", highLightedActivities, highLightedFlows, engConf.getActivityFontName(),
		engConf.getLabelFontName(), engConf.getAnnotationFontName(), engConf.getClassLoader(), 1.0, true);
	OutputStream out = null;
	byte[] buf = new byte[1024];
	int length;
	try {
		out = httpServletResponse.getOutputStream();
		while ((length = in.read(buf)) != -1) {
			out.write(buf, 0, length);
		}
	} catch (IOException e) {
		log.error("操作异常", e);
	} finally {
		IoUtil.closeSilently(out);
		IoUtil.closeSilently(in);
	}
}

注意看这里,如果这里用engConf.getProcessDiagramGenerator()获取Flowable默认的流程图生成器,生成的流程图是这个样子

ProcessDiagramGenerator diagramGenerator = engConf.getProcessDiagramGenerator();

在这里插入图片描述
这里我们需要创建两个类去继承DefaultProcessDiagramCanvas和DefaultProcessDiagramGenerator。
CustomProcessDiagramCanvas中增加一个方法drawActiveHighLight,用来生成当前节点,也可以写其他方法去实现自己想要的效果,如开始节点默认生成的是方形的,可以改成生成一个圆形效果。

CustomProcessDiagramGenerator中重写drawActivity方法,

// Draw highlighted activities
if (highLightedActivities.contains(flowNode.getId())) {
	if (StringUtil.containsAny(flowNode.getId(), "startEvent", "endEvent")
		|| StringUtil.equals(flowNode.getName(), "开始")
		|| StringUtil.equals(flowNode.getName(), "结束")) {
		// 开始结束节点设置为圆形
		((CustomProcessDiagramCanvas)processDiagramCanvas).drawStartOrEndEventHighLight((int) graphicInfo.getX(), (int) graphicInfo.getY(), (int) graphicInfo.getWidth(), (int) graphicInfo.getHeight());
	} else if(highLightedActivities.get(highLightedActivities.size()-1).equals(flowNode.getId())){
		// 这里判断是当前节点,设置为绿色高亮
		drawActiveHighLight((CustomProcessDiagramCanvas)processDiagramCanvas, bpmnModel.getGraphicInfo(flowNode.getId()));
	}else{
		drawHighLight(processDiagramCanvas, bpmnModel.getGraphicInfo(flowNode.getId()));
	}
}

2、显示节点信息

实现思路:在显示出高亮流程图后,请求后台获取流程节点坐标及节点信息,前端监听流程图的mousemove事件,通过弹窗位置、节点坐标和鼠标位置计算判断鼠标在哪个节点上,然后显示出对应的信息。

BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
List<Process> processes = bpmnModel.getProcesses();

List<UserTask> datas = new ArrayList<>();
processes.forEach(process -> {
	List<UserTask> userTasks = process.findFlowElementsOfType(UserTask.class);
	datas.addAll(userTasks);
});
List<ActivityVo> list = new ArrayList<>();
List<HistoricTaskInstance> taskInstances = historyService.createHistoricTaskInstanceQuery().processInstanceId(processInstanceId).list();
List<Task> taskList = taskService.createTaskQuery().processInstanceId(processInstanceId).list();
datas.forEach(userTask -> {
	ActivityVo vo = new ActivityVo();
	GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(userTask.getId());
	vo.setX(graphicInfo.getX());
	vo.setY(graphicInfo.getY());
	vo.setWidth(graphicInfo.getWidth());
	vo.setHeight(graphicInfo.getHeight());
	List<String> taskCandidates = getTaskCandidate(userTask);
	vo.setTaskCandidates(StringUtil.join(taskCandidates));
	vo.setAssigneeName(getTaskAssigneeName(userTask.getAssignee()));
	List<BladeFlow> flows = new ArrayList<>();
	vo.setFlows(flows);
	taskInstances.forEach(task -> {
		if (StringUtil.equals(task.getTaskDefinitionKey(), userTask.getId())) {
			BladeFlow flow = new BladeFlow();
			flow.setStatus("已结束");
			taskList.forEach(runtimeTask -> {
				if (StringUtil.equals(runtimeTask.getId(), task.getId())) {
					flow.setStatus(runtimeTask.isSuspended() ? "挂起" : "处理中");
				}
			});
			flow.setCreateTime(task.getCreateTime());
			flow.setEndTime(task.getEndTime());
			String durationTime = DateUtil.secondToTime(Func.toLong(task.getDurationInMillis(), 0L) / 1000);
			flow.setHistoryActivityDurationTime(durationTime);
			User assigneeUser = UserCache.getUserByTaskUser(task.getAssignee());
			flow.setAssignee(task.getAssignee());
			flow.setAssigneeName(Func.isNull(assigneeUser) ? "" : assigneeUser.getRealName());
			flows.add(flow);
		}
	});

	list.add(vo);
});
$('img', layero).attr('src', 'api/blade-flow/process/diagram-view?processInstanceId=' + that.options.processInstanceId);
$('img', layero).on('mousemove', function(e){
    let x = e.offsetX;
    let y = e.offsetY;
    showTaskInfo(x, y);
})
function showTaskInfo(x, y){
    let taskInfoWidth = 250;
    let dialogTop = parseInt($(dialogContainer).css('top').replace('px', ''));
    let dialogLeft = parseInt($(dialogContainer).css('left').replace('px', ''));
    let titleHeight = $('.layui-layer-title', dialogContainer).height();
    let imageX = dialogLeft;
    let imageY = dialogTop + titleHeight;
    $.each(userTaskData, function(index, item){
        if (x > item.x
            && y > item.y
            && (x < item.x + item.width)
            && (y < item.y + item.height)
        ) {
        	// 进到这里说明已经在这个节点上了,可以显示信息了
            if ($('.task-info-container[taskId="' + item.taskId + '"]', dialogContainer).length > 0){
            	// 进到这里说明已经显示信息了,不用再显示了
                return;
            }
            // 计算位置
            let top = imageY + item.y + item.height + 10;
            let left = imageX + item.x + (item.width / 2) - (taskInfoWidth / 2);
            item.top = top + 'px';
            item.left = left + 'px';
            item.triangleTop = (top - 10) + 'px';
            item.triangleLeft = (left + (taskInfoWidth / 2) - 10) + 'px';
            laytpl($('#task-info-tpl').html()).render(item, function (html) {
                $('img', dialogContainer).after(html);
            })
        } else {
        	// 进到这里说明鼠标已经移开了
            $('.task-info-container[taskId="' + item.taskId + '"]', dialogContainer).remove();
        }
    })
}
  • 5
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
Flowable是一个轻量级的工作流引擎,它具有可配置、可扩展和可重用的特性。它可以用于处理业务流程、审批流程、工作流等场景。 下面是一个Flowable工作流实战: 1. 创建流程定义文件 首先需要创建一个流程定义文件,它通常是一个XML文件,描述了流程中的各个节点、任务、流程变量等信息。可以使用Flowable Designer或者手动创建文件。例如,以下是一个简单的流程定义文件: ``` <?xml version="1.0" encoding="UTF-8"?> <definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:flowable="http://flowable.org/bpmn" targetNamespace="http://activiti.org/bpmn20" xsi:schemaLocation="http://www.omg.org/spec/BPMN/20100524/MODEL BPMN20.xsd http://flowable.org/bpmn http://flowable.org/xsd/bpmn/flowable-bpmn-2.0.xsd" id="simpleProcess"> <process id="myProcess" name="My process" isExecutable="true"> <startEvent id="startEvent" /> <sequenceFlow id="flow1" sourceRef="startEvent" targetRef="task1" /> <userTask id="task1" name="Task 1" flowable:assignee="${assignee}" /> <sequenceFlow id="flow2" sourceRef="task1" targetRef="endEvent" /> <endEvent id="endEvent" /> </process> </definitions> ``` 2. 部署流程定义文件 部署流程定义文件可以使用Flowable的API或者管理控制台。例如,以下是使用Flowable的API进行部署的示例代码: ``` ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); RepositoryService repositoryService = processEngine.getRepositoryService(); Deployment deployment = repositoryService.createDeployment() .addClasspathResource("simpleProcess.bpmn20.xml") .deploy(); ``` 3. 启动流程实例 启动流程实例可以使用Flowable的API或者通过调用REST API。例如,以下是使用Flowable的API进行流程实例启动的示例代码: ``` ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); RuntimeService runtimeService = processEngine.getRuntimeService(); Map<String, Object> variables = new HashMap<>(); variables.put("assignee", "user1"); ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("myProcess", variables); ``` 4. 处理任务 处理任务可以使用Flowable的API或者通过调用REST API。例如,以下是使用Flowable的API进行任务处理的示例代码: ``` ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); TaskService taskService = processEngine.getTaskService(); Task task = taskService.createTaskQuery().processInstanceId(processInstanceId).singleResult(); taskService.complete(task.getId()); ``` 5. 监控流程实例 可以使用Flowable的API或者Flowable的管理控制台进行流程实例监控。例如,以下是使用Flowable的API进行流程实例监控的示例代码: ``` ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); HistoryService historyService = processEngine.getHistoryService(); List<HistoricProcessInstance> processInstances = historyService.createHistoricProcessInstanceQuery().list(); ``` 以上是一个简单的Flowable工作流实战示例,可根据实际需求进行调整和扩展。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值