基于React的工作流 bpmn.js基本使用(2)-自定义右侧属性栏之更新业务属性到bpmn内

2,042 阅读3分钟

bpmn.js-右侧属性栏

如图所示:

image.png

想要使用右侧的属性栏就得安装一个名为bpmn-js-properties-panel的插件了。

  • 安装插件
npm install bpmn-js-properties-panpel --save-D  
  • 同样的记得要在项目中引入样式:
import 'bpmn-js-properties-panel/dist/assets/bpmn-js-properties-panel.css'  

在项目中我们使用自定义的属性栏,在流程设计的ModelDesigner中引入PropertiesView组件并使用自定义的BpmnModeler属性面板,PropertiesView组件内可以写正常业务逻辑,编辑完成之后,将属性同步更新到bpmn的xml文件内,给到后端解析使用,modeler是传入的当前流程信息的xml

// @ts-nocheck  
import React from 'react';  
import fileDrop from 'file-drops';  
// bpmn的左边工具栏以及编辑节点样式  
import 'bpmn-js/dist/assets/diagram-js.css';  
// bpmn的字体图标样式  
import 'bpmn-js/dist/assets/bpmn-font/css/bpmn.css';  
import 'bpmn-js/dist/assets/bpmn-font/css/bpmn-codes.css';  
import 'bpmn-js/dist/assets/bpmn-font/css/bpmn-embedded.css';  
// 自定义工具栏图标样式  
// 自定义的左边工具栏样式,必须使用 CSS Module  
import styles from '../../assets/Bpmn.module.less';  
import 'bpmn-js-bpmnlint/dist/assets/css/bpmn-js-bpmnlint.css';  
// 编辑工具组件  
import EditingTools from '@/components/editingTools';  
// import FullModal from '@/components/fullModal';  
import styless from './index.module.less';  
// 自定义Modeler  
import BpmnModeler from '@/components/modeler';  
 
import lintModule from 'bpmn-js-bpmnlint';  
import PropertiesView from '@/components/modeler/customPanel';  // 自定义右侧属性面板
// 而这个引入的是右侧属性栏里的内容  
import propertiesProviderModule from 'bpmn-js-properties-panel/lib/provider/camunda';

import {  
Message,  
Modal,  
Row,  
Col,  
Notification,  
Spin,  
} from 'antd';  
import flowableModdle from './flowable.json';  
let xmlStr = '';  
class ModelDesign extends React.Component {  
constructor(props) {  
super(props);  
}  
componentDidMount() {  
     
      this.bpmnModeler = new BpmnModeler({  
        container: '#canvas',  
        additionalModules: [  
          // 右边的属性栏 
          propertiesProviderModule,  
        ],  
        // 兼容flowable  
        moddleExtensions: {  
          flowable: flowableModdle,  
        },  
      });
      this.sttState({modeler:this.bpmnModeler})
      }
render() {  
const { svgVisible, svgSrc, loading } = this.state;  
return (  
<Spin spinning={loading}>  
<div className={styles.container}>  
<Row style={{ display: 'flex', flexFlow: 'nowrap' }}>  
<Col flex="auto">  
{/* 画布 */}  
<div className={styles.canvas} id="canvas" />  
</Col>  
<Col flex="308px">  
{/* 右侧自定义属性栏 */}  
<PropertiesView  
checkError={this.checkError}  
modeler={this.state.modeler}  
></PropertiesView>  
</Col>  
</Row>  
{/* 编辑工具 */}  
<EditingTools  
onOpenFIle={this.handleOpenFile}  
onSave={this.handleSave}  
onUndo={this.handleUndo}  
onRedo={this.handleRedo}  
onDownloadSvg={this.handleDownloadSvg}  
onDownloadXml={this.handleDownloadXml}  
onZoomIn={() => this.handleZoom(0.1)}  
onZoomOut={() => this.handleZoom(-0.1)}  
onZoomReset={() => this.handleZoom()}  
onPreview={this.handlePreview}  
/>  
</div>  
</Spin>  
);  
}  
}  
  
// 导出一个流程设计组件  
export default ModelDesign;  
  

流程图节点添加点击选中的事件

通过传递当前流程图的modeler,就是实例化的bpmn的流程图的信息,我们通过在流程的原型上添加选中的事件,通过点击的参数带出选中的流程图节点信息,比如,用户任务、服务任务等

     componentDidMount(){
     // 组件挂载完成之后,在modeler中添加一个选中的事件
     this.props.modeler.on('selection.changed',(e)=>{
     // 这个e.newSelection[0]就是每次选中的节点信息,可以用于区分不同的节点类型
     
     // 比如用户任务,选中之后,我们可以用来回显右侧属性栏的表单信息
     // 将选中的节点存在变量selectedElement  
        const selectedElement = e.newSelection[0];  
        console.log(selectedElement, '选中节点');  
        if (selectedElement) {  
          this.setState({  
            currentElement: selectedElement,  
          });  
  
      
        // 回显用户任务  
        if (selectedElement && selectedElement.type === 'bpmn:UserTask') {  
          const { id, name, $type: type } = selectedElement?.businessObject;  
          const { width, height } = selectedElement;  
          const {  
            name: modelName,  
            id: modelKey,  
          } = selectedElement.businessObject.$parent;  
          this.userTaskNodeInfoRef.current.setFieldsValue({  
            id,  
            name,  
            type,  
            width,  
            height,  
            modelName,  
            modelKey,  
          });  
        }
     })
     
     }

怎么更新节点信息

上文中我们保存了 当前点击的节点信息currentElement,可以使用bpmn.js提供的方法updateProperties来进行更新,下面代码,通过接受的属性,获取到模型的modeling来更新

// 更新自定义属性  
  updateProperties = (properties) => {  
    const modeling = this.props.modeler.get('modeling');  
    modeling.updateProperties(this.state.currentElement, properties);  
  };

下面以一个服务任务 更新属性作为示例,其他的任务也都同样的方式,只不过是创建标签的类型不同,下面的示例中有调用了俩次更新,一次是更新服务的委托实现类,一次是更新字段名

// 保存服务任务节点信息  
  saveServiceTaskNodeInfo = () => {  
    const settings = this.serviceTaskSettingRef.current.getFieldsValue();  
    // 属性  
    // 删除多余属性  
    const serviceTaskNodeInfoFormClone = JSON.parse(JSON.stringify(settings));  
    const properties = {};  
    for (const key in serviceTaskNodeInfoFormClone) {  
      if (serviceTaskNodeInfoFormClone.hasOwnProperty(key)) {  
        const value = serviceTaskNodeInfoFormClone[key];  
        if (value.length !== 0) {  
          properties[`flowable:${key}`] = Array.isArray(value)  
            ? value.toString()  
            : value;  
        }  
      }  
    }  
   
    // 节点字段名  
    let extensionElements = this.state.currentElement.businessObject.get(  
      'extensionElements',  
    );  
    if (!extensionElements) {  
      extensionElements = this.props.modeler  
        .get('moddle')  
        .create('bpmn:ExtensionElements');  
    }  
    //判断是否有服务委托类,并且字段名存在  
   
      extensionElements.values = [];  
      // 服务任务委托类  
      this.state.serviceClassList.forEach((item) => {  
        let field = [];  
        // 判断如果类型是字符串 就创建string类型的标签,  
        if (item.data[1].value == 'string') {  
          field = this.props.modeler.get('moddle').create('flowable:string');  
        }  
        // 判断如果类型是表达式 就创建expression类型的标签,  
        if (item.data[1].value == 'expression') {  
          field = this.props.modeler  
            .get('moddle')  
            .create('flowable:expression');  
        }  
        field['body'] = item.data[2].value;  
        const executeListener = this.props.modeler  
          .get('moddle')  
          .create('flowable:Field');  
        executeListener['name'] = item.data[0].value;  
        executeListener['string'] = field;  
        extensionElements.get('values').push(executeListener);  
      });  
      this.updateProperties({ extensionElements: extensionElements });  
  //  更新服务任务流程  
    this.updateProperties(properties);  
  };