Application development platform integrated workflow - process modeling function rollback and jump

background

For the problem of unfriendly process settings, domestic DingTalk designed and implemented a set of process modeling mode separately, which has nothing to do with the bpmn specification. Someone imitated it and made it open source ( https://github.com/StavinLi/Workflow -Vue3 ), the effect diagram is as follows:

the general principle of implementation is based on infinitely nested child nodes, output json data, and pass it to the backend. After the backend parses, it calls the api of the Camunda engine, converts it into a process model, and then persists it.

**This mode, compared with the process modeling of the bpmn2.0 specification that comes with Camunda, is much more friendly, but it also introduces new problems, and it is impossible to set "jump flow" between links. **The "jump transfer" mentioned here actually includes two directions of transfer, one is to jump from the current link to a non-direct follow-up link, and the other is to fall back from the current link to a certain pre-order link.

The above requirements cannot be solved through routing branches. For the native BPMN model, you can draw edges between the start node and the target node, and set conditions on the edges, and this set of imitation DingTalk process modeling mode, which fundamentally makes the solution of "drawing edges" unfeasible, what should I do?

Implementation ideas

In the existing process modeling mode, it is necessary to adapt to realize the jump flow. The specific implementation idea is to store the links that can be rolled back or skipped in each link by custom configuration, and use it as a link configuration part.
Since it is designed by itself, the degree of freedom is higher, and the type of jump flow can be distinguished by adding attributes, whether it is a fallback or a jump. In the native bpmn, the edge drawn has no type. The normal edge, the default edge, the return edge, and the jump edge are all implemented in the same way, and conditions can be added. To distinguish between rollback and jump, only by setting the agreed conditions Indirect implementations, such as setting variables such as ${reject==true} to mark fallbacks, are not elegant.

Thinking about key issues

Is the default configuration fallback to the initiation link and the previous link?

Rollback can be implemented by configuration to restrict users, and arbitrary rollback is not allowed. However, it is a common requirement to fall back to the initiation link and the previous link. Whether these two situations are handled by the platform by default, that is, it can be rolled back without configuration, and then only configure the fallback link for other situations that need to be processed OK?

The default configuration of the system can indeed reduce a part of the configuration workload, but it may destroy the overall controllability and standardization of the process. For example, a long process is divided into three major stages in terms of management. In the second stage, it is not allowed to fall back to the initiation link. Once the default processing is added, this business constraint will be broken. In addition, for the following two situations, rollback is not allowed:
1. Multi-person countersigning link, before all participants have processed it
2. The link currently in the routing branch, directly rolls back to the link on the main branch

Considering the above scenarios and limitations, it is finally decided that the system will not be configured by default, and the process modeler will configure it according to actual business needs.

Whether the link name is stored redundantly

During process modeling, when configuring the list of links that a certain link can jump to and fall back to, it is no problem to use the link identifier for logical judgment, and use the link name for display. A question is involved, that is, whether the link name should be stored redundantly. In terms of friendliness, redundant storage is required. But redundant storage means that updates need to be synchronized, which is not easy to achieve. The user configures the link jump or rollback first, and then changes the name of the target link. The link jump or rollback configuration is actually imperceptible.

In order to solve this problem, there are two solutions:
one is to simply not redundantly store the link names in the link list configuration of the jump and fallback, but only save the link identifier, dynamically find out the link name, and display it to the user. It can ensure that the link names are consistent in real time, but the processing is cumbersome and involves model analysis and processing.
The second is to still carry out redundant storage. In the model saving link, traverse and update, that is, the query type is the link of initiation or processing. According to the process definition identifier and link identifier, the list configuration of the links to jump to and fall back to is updated in batches.

The problem with Solution 2 is that the data in the table in the back-end library is updated, but the model in the front-end json format is not actually updated. If the model is exported and then imported, it will lead to wrong model migration results. Therefore, in essence, it needs to be updated from the front end, but it is quite troublesome to do it from the front end.

This problem is put on hold for the time being, and redundant storage is performed first, without synchronous update, and the possibility of link name modification is low. If synchronous update is not implemented, it can be updated manually through configuration, and the workload is small.

Front-end implementation

configuration extension

The front end puts the configuration information into the config attribute of the node, which is paralleled with the personnel configuration personConfig and the permission configuration permissionConfig, and expands and adds the backNodeList and the jump link list jumpNodeList. Theoretically, the two types of nodes, the initiation link and the handling link, are handled manually, which involves the need for "jumping transfer".
The configurations of backNodeList and jumpNodeList are the same, because the process may allow the current link to roll back or jump to multiple links, so it is an array, including the target link's identification and name. Two key attributes are Can.

Examples are as follows:

{
    
    
	"name": "填报",
	"id": "root",
	"type": "ROOT",
	"config": {
    
    
		"permissionConfig": [{
    
    
			"areaCode": "applyArea",
			"permission": "EDITABLE"
		}, {
    
    
			"areaCode": "organizationApproval",
			"permission": "READONLY"
		}, {
    
    
			"areaCode": "hrApproval",
			"permission": "INVISIBLE"
		}],
		"jumpNodeList": [{
    
    
			"id": "node2268_3ea5_a5db_15b0",
			"name": "人事审批"
		}]
	},
	"branchList": [],
	"child": {
    
    
		"name": "部门审批",
		"id": "node1938_8b28_c3ed_030f",
		"type": "HANDLE",
		"config": {
    
    
			"personConfig": {
    
    
				"mode": "COUNTERSIGN",
				"setAssigneeFlag": "YES",
				"userGroup": "99",
				"userGroupName": "系统管理员"
			},
			"permissionConfig": [{
    
    
				"areaCode": "applyArea",
				"permission": "READONLY"
			}, {
    
    
				"areaCode": "organizationApproval",
				"permission": "READONLY"
			}, {
    
    
				"areaCode": "hrApproval",
				"permission": "READONLY"
			}]
		},
		"child": {
    
    
			"name": "人事审批",
			"id": "node2268_3ea5_a5db_15b0",
			"type": "HANDLE",
			"config": {
    
    
				"personConfig": {
    
    
					"mode": "NORMAL",
					"setAssigneeFlag": "YES",
					"userGroup": "99",
					"userGroupName": "系统管理员"
				},
				"permissionConfig": [{
    
    
					"areaCode": "applyArea",
					"permission": "READONLY"
				}, {
    
    
					"areaCode": "organizationApproval",
					"permission": "READONLY"
				}, {
    
    
					"areaCode": "hrApproval",
					"permission": "READONLY"
				}],
				"backNodeList": [{
    
    
					"id": "root",
					"name": "填报"
				}, {
    
    
					"id": "node1938_8b28_c3ed_030f",
					"name": "部门审批"
				}]
			},
			"child": {
    
    }
		}
	}
}

link configuration

For the initiation link, it is the starting point of the process, and there is no rollback problem. Can the jump be realized through the routing function? Think about it, there are actually multiple scenarios.
Scenario 1: A list, when a certain rule is met, jump directly to a certain link in the middle, and this rule may not be clear enough for the system to automatically judge and process, and it must be manually judged whether the jump should be performed.
Scenario 2: An order goes to a certain stage of approval, and if there is a problem, it returns to the initiation stage and the applicant makes adjustments. After the adjustment, he does not want to go through the stage again, but wants to jump directly to rejection The specific scenario is similar to contract approval, where multi-functional departments participate in the review, such as finance, legal, etc. If problems are found in the legal review process and need to be adjusted, I don’t want to go through the financial review process again.
In summary, the initiation link still needs to set the jump link setting.

The processing link is a manual process link, which requires both the rollback function and the jump function.

Take the jump link configuration as an example, as shown
image.png
in the following figure: First, after clicking the "Add" button, a dialog box will pop up to display all target links that can be jumped to. The target link must meet the following conditions: 1.
Type It can only be the initiation link and the processing link, and cannot jump to the routing node. If the jump to the routing node is allowed, it will seriously damage the normative and restrictive nature of the workflow as a process template.
2. You need to exclude yourself, jump to yourself, endless loop...
3. Later expand the node type, such as automatic processing links (such as sending emails), it can be expanded according to the situation, and it is allowed to be the target node.

In addition, there is another place here. For the processing link, if it is a countersign, from a business point of view, it should be allowed to fall back or jump to this link, but an error will be reported when calling Camunda's underlying API. Here is just a mention, in the next chapter I will specifically address this issue.

backend implementation

entity configuration

The entity attributes of the rollback link and the jump link of the link configuration are actually exactly the same. If the same database table is used for storage, an additional attribute is required for the entity to distinguish between rollback and jump. An additional field is added to the library table, and the code Additional logical judgments.
Based on the high efficiency of the platform's low-code configuration, first realize the configuration entity of the fallback link, and then realize the configuration of the jump link by copying the new functions.
The following is the configuration entity information attribute list of the fallback link
image.png
as follows:
image.png

Model parsing and persistence

When the process model is converted, the reading link cooperates with the backNodeList attribute under the config attribute

    private void configBackNodeList(String tempVersion, String id,String configString) {
    
    
        if(StringUtils.isNoneBlank(configString)) {
    
    

            List<WorkflowBackNodeConfig> backNodeList = new ArrayList<>();
            JSONArray jsonArray = JSON.parseArray(configString);
            for (int i = 0; i < jsonArray.size(); i++) {
    
    
                JSONObject jsonObject = jsonArray.getJSONObject(i);
                WorkflowBackNodeConfig entity = new WorkflowBackNodeConfig();
                entity.setTargetNodeId(jsonObject.getString("id"));
                entity.setTargetNodeName(jsonObject.getString("name"));
                backNodeList.add(entity);
            }
            workflowBackNodeConfigService.updateConfig(tempVersion, id, backNodeList);
        }

    }

The service method, updateConfig, is as follows. It uses the mode of clearing the configuration first and then creating it. By the way, it clears up the garbage data left over due to node changes.

    @Override
    public void updateConfig(String processDefinitionId, String nodeId, List<WorkflowBackNodeConfig> jumpNodeList) {
    
    
        // 先清空配置
        QueryWrapper<WorkflowBackNodeConfig> queryWrapper=new QueryWrapper<>();
        queryWrapper.lambda().eq(WorkflowBackNodeConfig::getProcessDefinitionId,processDefinitionId)
                .eq(WorkflowBackNodeConfig::getNodeId,nodeId);
        remove(queryWrapper);
        // 后生成配置
        int orderNo=0;
        for(WorkflowBackNodeConfig entity:jumpNodeList){
    
    
            orderNo++;
            entity.setProcessDefinitionId(processDefinitionId);
            entity.setNodeId(nodeId);
            entity.setOrderNo(StringUtils.leftPad(String.valueOf(orderNo),2,"0"));
            add(entity);
        }

    }

Development platform information

Platform name: One Two Three Development Platform
Introduction: Enterprise-level general development platform
Design information: csdn column
Open source address: Gitee
open source protocol: MIT
open source is not easy, welcome to favorite, like, comment.

Guess you like

Origin blog.csdn.net/seawaving/article/details/132508061