bpmn.js-右侧属性栏
如图所示:
想要使用右侧的属性栏就得安装一个名为
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);
};