bpmn-js 改造(一)添加会签节点

bpmn-js应该是使用最广最普遍的一个流程设计器。前段时间自己写了个流程设计器,为了更好的完善自己写的设计器,所以拿bpmn-js来进行一次研究。

bpmn-js 网上各种帖子,但大部分都是停留在测试、学习层面,基本很少有结合企业业务来扩展的,所以我这里结合业务记录下bpmn-js的使用

  • 流程会签:就是流程运转过程中需要提交给多个人进行审批,每个人可以发表意见,而且会签也存在一票否决、比例决策、全票决策等策略。为了实现该功能,第一步应该是要绘制这样一个节点,表示进入到会签,后台根据这个特殊节点进行代码处理。

直接上图
在这里插入图片描述
要实现这个功能要完成以下

  • 扩展Palette,定义customPalette,将会签任务节点放入PalettePanel区域
  • 定义会签任务相关属性定义

实现customPalette大概文件如下:
在这里插入图片描述
第一步定义:CustomPalette.js

export default class CustomPalette {
  constructor(create, elementFactory, palette) {
    this.create = create;
    this.elementFactory = elementFactory;
    palette.registerProvider(this);
  }


  // 这个是绘制palette的核心,函数名不要变
  getPaletteEntries() {
    const elementFactory = this.elementFactory;
    const create = this.create;

    function dragEventFactory(type) {
      return function (event) {
        const taskShape = elementFactory.create('shape', {
          type: type
        });
        create.start(event, taskShape);
      };
    }

    return {
      'create.user-sign': {
        title: '流程会签',    // 鼠标悬浮到节点上显示的文字
        className: 'goForm gf-huiqianrenwu',   // 样式名
        action: {      // 操作该节点时会触发的事件,此时只注册一个拖动事件即可,否则拖动时没有效果
          dragstart: dragEventFactory('bpmn:Task')
        }
      }
    };
  }
}
CustomPalette.$inject = [
  'create',
  'elementFactory',
  'palette'
];

第二步:定义CustomRenderer.js

import BaseRenderer from 'diagram-js/lib/draw/BaseRenderer';
import { customElements, customConfig } from './util';
import { append as svgAppend, create as svgCreate } from 'tiny-svg';
import SVGUtil from "../utils/svgUtil";
import GoUserSignNode from "../bpmnExtend/goFlowNode/goUserSignNode";
import {GoingUtils} from 'goingutils';

const HIGH_PRIORITY = 1500; // 最高优先级

export default class CustomRenderer extends BaseRenderer {
  // 继承BaseRenderer
  constructor(eventBus, bpmnRenderer) {
    super(eventBus, HIGH_PRIORITY);
    this.bpmnRenderer = bpmnRenderer;
  }

  canRender(element) {
    return !element.labelTarget;
  }

  _addSvgSymbol(nodeItem) {
    let symbolNode = SVGUtil.create("use");
    let A = 0;
    // @ts-ignore
    SVGUtil.setAttrs(symbolNode, {"xlink:href": "#"+nodeItem.iconName,fill: "#666"});
    return symbolNode;
  };

  _addBackCircleNode(nodeItem) {
    let outUseNode = SVGUtil.create("use");
    SVGUtil.setAttrs(outUseNode, {
      "xlink:href": "#icon_back_circle_"+nodeItem.getId()
    });
    let rectNode = SVGUtil.create("rect");
    SVGUtil.setAttrs(rectNode, {
      "rx": nodeItem.getAttr("rx"),
      "ry": nodeItem.getAttr("ry"),
      "width":nodeItem.getAttr("width"),
      "height":nodeItem.getAttr("height"),
      "fill": nodeItem.getAttr("nodeBgColor"),
      "id": "icon_back_circle_"+nodeItem.getId(),
      "stroke": nodeItem.getAttr("stroke"),
      "stroke-width":nodeItem.getAttr("strokeWidth")
    });
    outUseNode.appendChild(rectNode);
    return outUseNode;
  };

  /**
   * 添加节点的字
   * @param gGroupNode
   * @param element
   */
  addTextNode(gGroupNode,element){
    let tspan = SVGUtil.create("tspan");
    SVGUtil.setAttrs(tspan, {
      "x": "28",
      'y':'43',
    });
    tspan.innerHTML=(element.businessObject&&element.businessObject.name)||"会签节点";
    let textNode = SVGUtil.create("text");
    SVGUtil.setAttrs(textNode, {
      "class": "djs-label",
      'font-size':'12px',
      'font-weight':'normal',
      'fill':'black',
      "font-family": "Arial, sans-serif",
    });
    textNode.appendChild(tspan);
    gGroupNode.appendChild(textNode);
    element.textNode=textNode;
  }

  /**
   * 添加用于显示的节点
   * @param showNodeParent
   * @param element
   * @returns {g}
   */
  addShowNode(showNodeParent,element) {
    element.nodeType="userSign";

    function getIconGgroupNode(nodeItem) {
      // @ts-ignore
      let id = `node_icon_use_` + nodeItem.getId();
      let g = SVGUtil.create("g");
      SVGUtil.setAttrs(g, {
        fill: "#f00",
        id: id
      });
      return g;
    }

    let nodeItem=new GoUserSignNode({id:'user-sign-node-'+GoingUtils.getUUid(10)});
    let gGroupNode = getIconGgroupNode(nodeItem);
    //获取节点的背景元素
    gGroupNode.appendChild(this._addBackCircleNode(nodeItem));
    //添加节点svg图元素
    gGroupNode.appendChild(this._addSvgSymbol(nodeItem));
    //添加字体
    this.addTextNode(gGroupNode,element);
    //将最外层的group元素放到容器中
    svgAppend(showNodeParent, gGroupNode);
    return gGroupNode;
  }

  /**
   * 开始自定义图形绘制
   * @param parentNode
   * @param element
   * @returns {*}
   */
  drawShape(parentNode, element) {
    const type = element.type; // 获取到类型
    console.log(element,"------element--------")
    // 所有节点都会走这个函数,所以此时只限制,需要自定义的才去自定义,否则仍显示bpmn默认图标
    if (customElements.includes(type)) {
      const {url, attr} = customConfig['cake'];
      const gGroupNode= this.addShowNode(parentNode,element);
      // const customIcon = svgCreate('image', {...attr, href: url});
      element['width'] = attr.width;
      element['height'] = attr.height;
      svgAppend(parentNode, gGroupNode);
      return gGroupNode;
    }
    const shape = this.bpmnRenderer.drawShape(parentNode, element);
    return shape;
  }


  getShapePath(shape) {
    return this.bpmnRenderer.getShapePath(shape);
  }
}

CustomRenderer.$inject = ['eventBus', 'bpmnRenderer'];

第三步:定义index.js

import CustomPalette from './CustomPalette';
import CustomRenderer from './CustomRenderer';

export default {
  __init__: ['customPalette', 'customRenderer'],
  customPalette: ['type', CustomPalette],
  customRenderer: ['type', CustomRenderer]
};

第三步:定义util.js


// 自定义元素的类型,此时我们只需要自定义一种节点,所以数组只有一个元素
const customElements = ['bpmn:Task'];
const customConfig = {
  // 自定义元素的配置
  cake: {
    url: "",
    attr: {x: 0, y: 0, width: 98, height: 80}
  }
};

export {customElements, customConfig};

第五:则在调用的地方申明下:

import customModule from '../customPalette';
...
  const canvas = this.$refs.canvas;
      // 生成实例
      this.bpmnModeler = new BpmnModeler({
        additionalModules: [ customModule ],
        container: canvas
      });

到此就完成了流程会签节点的绘制扩展了。下一节再讲会签节点的属性设置信息

  • 5
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 10
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值