03 flowable节点的自定义属性扩展

项目地址:https://gitee.com/lwj/flowable.git 分支flowable-base
视频地址:https://www.bilibili.com/video/av79774697/
业务场景:
在实际业务中,我们有可能对一些节点做一些控制,比方说流程到这个节点的时候,可以编辑表单的某些字段,进而进一步的审批流转 。如何扩展系欸但的属性呢,请看效果和实际扩展代码。

效果如下:在这里插入图片描述

新增一个节点属性

修改stencilset_bpmn.json 添加一个package;

{
      "name": "nodetypepackage",
      "properties": [
        {
          "id": "nodetype",
          "type": "dragon-nodetype-combobox",
          "title": "节点类型",
          "value": "",
          "description": "节点类型",
          "popular": true
        }
      ]
    }

在 stencilset_bpmn.json找到UserTask这个节点信息

{
“type” : “node”,
“id” : “UserTask”,
“title” : “\u7528\u6237\u4efb\u52a1”,
“description” : “\u4efb\u52a1\u624b\u52a8\u5206\u914d\u7ed9\u4e00\u4e2a\u7279\u5b9a\u7684\u4eba”,
“view” : “<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<svg\n xmlns=“http://www.w3.org/2000/svg”\n xmlns:svg=“http://www.w3.org/2000/svg”\n xmlns:oryx=“http://www.b3mn.org/oryx”\n xmlns:xlink=“http://www.w3.org/1999/xlink”\n\n width=“102”\n height=“82”\n version=“1.0”>\n \n oryx:magnets\n \t<oryx:magnet oryx:cx=“1” oryx:cy=“20” oryx:anchors=“left” />\n \t<oryx:magnet oryx:cx=“1” oryx:cy=“40” oryx:anchors=“left” />\n \t<oryx:magnet oryx:cx=“1” oryx:cy=“60” oryx:anchors=“left” />\n \t\n \t<oryx:magnet oryx:cx=“25” oryx:cy=“79” oryx:anchors=“bottom” />\n \t<oryx:magnet oryx:cx=“50” oryx:cy=“79” oryx:anchors=“bottom” />\n \t<oryx:magnet oryx:cx=“75” oryx:cy=“79” oryx:anchors=“bottom” />\n \t\n \t<oryx:magnet oryx:cx=“99” oryx:cy=“20” oryx:anchors=“right” />\n \t<oryx:magnet oryx:cx=“99” oryx:cy=“40” oryx:anchors=“right” />\n \t<oryx:magnet oryx:cx=“99” oryx:cy=“60” oryx:anchors=“right” />\n \t\n \t<oryx:magnet oryx:cx=“25” oryx:cy=“1” oryx:anchors=“top” />\n \t<oryx:magnet oryx:cx=“50” oryx:cy=“1” oryx:anchors=“top” />\n \t<oryx:magnet oryx:cx=“75” oryx:cy=“1” oryx:anchors=“top” />\n \t\n \t<oryx:magnet oryx:cx=“50” oryx:cy=“40” oryx:default=“yes” />\n </oryx:magnets>\n <g pointer-events=“fill” oryx:minimumSize=“50 40”>\n\t<rect id=“text_frame” oryx:anchors=“bottom top right left” x=“1” y=“1” width=“94” height=“79” rx=“10” ry=“10” stroke=“none” stroke-width=“0” fill=“none” />\n\t<rect id=“bg_frame” oryx:resize=“vertical horizontal” x=“0” y=“0” width=“100” height=“80” rx=“10” ry=“10” stroke=”#bbbbbb" stroke-width=“1” fill="#f9f9f9" />\n\t\t<text \n\t\t\tfont-size=“12” \n\t\t\tid=“text_name” \n\t\t\tx=“50” \n\t\t\ty=“40” \n\t\t\toryx:align=“middle center”\n\t\t\toryx:fittoelem=“text_frame”\n\t\t\tstroke="#373e48">\n\t\t\n\t\n\t<g id=“userTask” transform=“translate(3,3)”>\n\t\t<path oryx:anchors=“top left”\n \t\tstyle=“fill:#d1b575;stroke:none;”\n \t\t d=“m 1,17 16,0 0,-1.7778 -5.333332,-3.5555 0,-1.7778 c 1.244444,0 1.244444,-2.3111 1.244444,-2.3111 l 0,-3.0222 C 12.555557,0.8221 9.0000001,1.0001 9.0000001,1.0001 c 0,0 -3.5555556,-0.178 -3.9111111,3.5555 l 0,3.0222 c 0,0 0,2.3111 1.2444443,2.3111 l 0,1.7778 L 1,15.2222 1,17 17,17” \n />\n\t\t\n\t\n \n\t<g id=“parallel”>\n\t\t<path oryx:anchors=“bottom” fill=“none” stroke="#bbbbbb" d=“M46 70 v8 M50 70 v8 M54 70 v8” stroke-width=“2” />\n\t\n\t\n\t<g id=“sequential”>\n\t\t<path oryx:anchors=“bottom” fill=“none” stroke="#bbbbbb" stroke-width=“2” d=“M46,76h10M46,72h10 M46,68h10”/>\n\t\n\t\n\n\t<g id=“compensation”>\n\t\t<path oryx:anchors=“bottom” fill=“none” stroke="#bbbbbb" d=“M 62 74 L 66 70 L 66 78 L 62 74 L 62 70 L 58 74 L 62 78 L 62 74” stroke-width=“1” />\n\t\n \n",
“icon” : “activity/list/type.user.png”,
“groups” : [ “\u4efb\u52a1” ],
“propertyPackages” : [ “overrideidpackage”, “namepackage”, “documentationpackage”, “asynchronousdefinitionpackage”, “exclusivedefinitionpackage”, “executionlistenerspackage”, “multiinstance_typepackage”, “multiinstance_cardinalitypackage”, “multiinstance_collectionpackage”, “multiinstance_variablepackage”, “multiinstance_conditionpackage”, “isforcompensationpackage”, “usertaskassignmentpackage”, “formkeydefinitionpackage”, “formreferencepackage”, “duedatedefinitionpackage”, “prioritydefinitionpackage”, “formpropertiespackage”, “tasklistenerspackage”, “skipexpressionpackage”,“nodetypepackage” ],
“hiddenPropertyPackages” : [ ],
“roles” : [ “Activity”, “sequence_start”, “sequence_end”, “ActivitiesMorph”, “all” ]
}

编写angularJS脚本

在properties.js 配置模板;

 "dragon-nodetype-combobox": {
        "readModeTemplateUrl": "editor-app/configuration/properties/dragonnodetype-combobox-value-template.html",
        "writeModeTemplateUrl": "editor-app/configuration/properties/dragonnodetype-combobox-property-write-template.html"
    }
模板的内容

dragonnodetype-combobox-value-template.html 内容为:
<span>{{property.text}}</span>
dragonnodetype-combobox-property-write-template.html 内容为
 <div ng-controller="DragonNodetypeComboboxCtrl">
    <select ng-init="item = property.value" ng-model="item" ng-change="comboValueChanged(item)"
            ng-options="item.sn as item.name for item in nodeTypes">
    </select>
</div>

编写js控制器

properties-dragon-combobox-controller.js

angular.module('flowableModeler').controller('DragonNodetypeComboboxCtrl',
    [ '$scope', '$modal', '$http', function($scope, $modal, $http) {
        if ($scope.property.value == undefined && $scope.property.value == null) {
            $scope.property.value = '';
        }
        //请求数据
        //url 你可以请求你后台的rest接口来获取数据对象
        $http({
            method: 'GET',
            url: FLOWABLE.URL.getNodeProertyInfos('node_type')
        }).then(function successCallback(response) {
            $scope.nodeTypes = response.data.data;
        }, function errorCallback(response) {
            // 请求失败执行代码
        });
        $scope.comboValueChanged = function (item) {
            $scope.property.value = item;
            for (var i = 0; i < $scope.nodeTypes.length; i++) {
                if ($scope.nodeTypes[i].sn == item) {
                    $scope.property.text = $scope.nodeTypes[i].name;
                }
            }
            $scope.updatePropertyInModel($scope.property);
        };
    }]);

配置引用

在index.html中加入自定的js

<script src="editor-app/configuration/properties-dragon-combobox-controller.js" type="text/javascript"></script>

后台配置解析我们的节点属性

编写一个自定义的解析器

记住一定要继承UserTaskJsonConverter

public class BruceUserTaskJsonConverter extends UserTaskJsonConverter {

    public static void fillTypes(Map<String, Class<? extends BaseBpmnJsonConverter>> convertersToBpmnMap,
                                 Map<Class<? extends BaseElement>, Class<? extends BaseBpmnJsonConverter>> convertersToJsonMap) {
        fillJsonTypes(convertersToBpmnMap);
        fillBpmnTypes(convertersToJsonMap);
    }

    public static void setCustomTypes(Map<String, Class<? extends BaseBpmnJsonConverter>> convertersToBpmnMap,
                                 Map<Class<? extends BaseElement>, Class<? extends BaseBpmnJsonConverter>> convertersToJsonMap) {
        removeTypes(convertersToBpmnMap,convertersToJsonMap);
        fillTypes(convertersToBpmnMap,convertersToJsonMap);
    }

    public static void removeTypes(Map<String, Class<? extends BaseBpmnJsonConverter>> convertersToBpmnMap,
                                   Map<Class<? extends BaseElement>, Class<? extends BaseBpmnJsonConverter>> convertersToJsonMap) {
        convertersToJsonMap.remove(UserTask.class);
        convertersToBpmnMap.remove(StencilConstants.STENCIL_TASK_USER);
    }

    public static void fillJsonTypes(Map<String, Class<? extends BaseBpmnJsonConverter>> convertersToBpmnMap) {
        convertersToBpmnMap.put(STENCIL_TASK_USER, BruceUserTaskJsonConverter.class);
    }

    public static void fillBpmnTypes(
            Map<Class<? extends BaseElement>, Class<? extends BaseBpmnJsonConverter>> convertersToJsonMap) {
        convertersToJsonMap.put(UserTask.class, BruceUserTaskJsonConverter.class);
    }

    @Override
    public void convertToJson(BaseElement baseElement, ActivityProcessor processor, BpmnModel model, FlowElementsContainer container, ArrayNode shapesArrayNode, double subProcessX, double subProcessY){
        super.convertToJson(baseElement, processor, model, container, shapesArrayNode, subProcessX, subProcessY);
    }

    @Override
    protected FlowElement convertJsonToElement(JsonNode elementNode, JsonNode modelNode,
                                               Map<String, JsonNode> shapeMap) {
        UserTask flowElement = (UserTask) super.convertJsonToElement(elementNode, modelNode, shapeMap);
        List<CustomProperty> customProperties = new ArrayList<>();
        // 扩展 节点类型
        String nodetype = getPropertyValueAsString(FlowConstant.NODE_TYPE, elementNode);
        if (StringUtils.isNotBlank(nodetype)) {
            CustomProperty nodeType = this.createProperty(FlowConstant.NODE_TYPE, nodetype);
            customProperties.add(nodeType);
        }
        if (CollectionUtils.isNotEmpty(customProperties)) {
            flowElement.setCustomProperties(customProperties);
        }
        return flowElement;
    }

    /**
     * 创建自定义属性
     *
     * @param propertyName  属性名称
     * @param propertyValue 属性值
     */
    private CustomProperty createProperty(String propertyName, String propertyValue) {
        CustomProperty customProperty = new CustomProperty();
        customProperty.setId(propertyName);
        customProperty.setName(propertyName);
        customProperty.setSimpleValue(propertyValue);
        return customProperty;
    }
}

bean的初始化

public class CustomPropertyInit {

    public CustomPropertyInit(){
        Map<Class<? extends BaseElement>, Class<? extends BaseBpmnJsonConverter>> convertersToJsonMap = BpmnJsonConverter.convertersToJsonMap;
        Map<String, Class<? extends BaseBpmnJsonConverter>> convertersToBpmnMap = BpmnJsonConverter.convertersToBpmnMap;
        //添加自定义的任务json转化器
        BruceUserTaskJsonConverter.setCustomTypes(convertersToBpmnMap, convertersToJsonMap);
    }

}

spring定义bean

/**
     * 自定义节点属性初始化
     */
    @Bean
    public CustomPropertyInit createCustomPropertyInit() {
        return new CustomPropertyInit();
    }
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小学生05101

flowable

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值