100字范文,内容丰富有趣,生活中的好帮手!
100字范文 > vue中使用bpmn-js绘制流程图 并实现汉化 自定义Palette及ContextPad。

vue中使用bpmn-js绘制流程图 并实现汉化 自定义Palette及ContextPad。

时间:2022-08-21 00:56:05

相关推荐

vue中使用bpmn-js绘制流程图 并实现汉化 自定义Palette及ContextPad。

一、认识bpmn-is

bpmn-js是一个BPMN2.0渲染工具包和web建模器, 使得画流程图的功能在前端来完成。

效果图如下(改造后):

二、在vue基本使用

安装bpmn-js

npm install --save bpmn-js我用的是6.3.4版本

在main.js中移入相关样式

// bpmn绘图工具的样式import 'bpmn-js/dist/assets/diagram-js.css'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'

在.vue文件中使用

<template><div id="app"><div class="my-card"><el-row><el-col :span="20"><el-form@submit.native.prevent:model="queryParams"ref="queryForm"size="small":inline="true"class="my-search"><el-form-item label="流程编码" prop="code"><el-inputv-model="queryParams.code"placeholder="请输入流程编码"clearable/></el-form-item><el-form-item label="流程名称" prop="name"><el-inputv-model="queryParams.name"placeholder="请输入流程名称"clearable/></el-form-item><el-form-item label="所属平台" prop="name"><el-selectv-model="queryParams.platform"placeholder="请选择所属平台"style="width: 100%"clearable><el-optionv-for="item in []":key="item.id":label="item.label":value="item.id"></el-option></el-select></el-form-item><el-form-item><el-button size="mini" type="primary" @click="handleSave">保存</el-button></el-form-item></el-form></el-col><el-col :span="4" style="text-align: right"><el-button type="primary" @click="handleBack" size="mini">返回</el-button></el-col></el-row></div><div class="container"><div class="designer"></div><!-- 创建一个canvas画布 npmn-js是通过canvas实现绘图的,并设置ref让vue获取到element --><div class="bpmn-canvas" ref="canvas"></div><!-- 右侧panel --><properties-viewv-if="bpmnModeler":modeler="bpmnModeler"></properties-view><!-- 把操作按钮写在这里面有需要的可以放开(删) --><!-- <div class="action"><el-upload action class="upload-demo" :before-upload="openBpmn"><el-button icon="el-icon-folder-opened"></el-button></el-upload><el-buttonclass="new"icon="el-icon-circle-plus"@click="newDiagram"></el-button><el-button icon="el-icon-download" @click="downloadBpmn"></el-button><el-button icon="el-icon-picture" @click="downloadSvg"></el-button><a hidden ref="downloadLink"></a></div> --></div></div></template><script>import BpmnModeler from "bpmn-js/lib/Modeler";// 工具栏相关// 汉化文件import customTranslate from "./CustomTranslate";// 右侧context-pad面板组件import PropertiesView from "@/components/custom-properties-panel/PropertiesView";// 自定义context-pad文件import CustomContextPad from "./CustomContextPad";// 自定义左侧palette文件import CustomPalette from "./CustomPalette";export default {components: {PropertiesView,},data() {return {queryParams: {name: null,},bpmnModeler: null,canvas: null,bpmnTemplate: `<bpmn:definitions xmlns:xsi="/2001/XMLSchema-instance" xmlns:bpmn="/spec/BPMN/0524/MODEL" xmlns:bpmndi="/spec/BPMN/0524/DI" xmlns:dc="/spec/DD/0524/DC" xmlns:di="/spec/DD/0524/DI" id="Definitions_1oszlza" targetNamespace="http://bpmn.io/schema/bpmn"><bpmn:process id="Process_0qbzwnl" name="测试" isExecutable="true"><bpmn:startEvent id="StartEvent_1142pjw" name="开始"><bpmn:outgoing>Flow_0udz675</bpmn:outgoing></bpmn:startEvent><bpmn:task id="Activity_1umsb7z" name="审批"><bpmn:incoming>Flow_0udz675</bpmn:incoming><bpmn:outgoing>Flow_1fwu6d6</bpmn:outgoing></bpmn:task><bpmn:sequenceFlow id="Flow_0udz675" sourceRef="StartEvent_1142pjw" targetRef="Activity_1umsb7z" /><bpmn:task id="Activity_11qrnub" name="执行"><bpmn:incoming>Flow_1fwu6d6</bpmn:incoming><bpmn:outgoing>Flow_0gs9y2g</bpmn:outgoing></bpmn:task><bpmn:sequenceFlow id="Flow_1fwu6d6" sourceRef="Activity_1umsb7z" targetRef="Activity_11qrnub" /><bpmn:endEvent id="Event_09ptfxq" name="结束"><bpmn:incoming>Flow_0gs9y2g</bpmn:incoming></bpmn:endEvent><bpmn:sequenceFlow id="Flow_0gs9y2g" sourceRef="Activity_11qrnub" targetRef="Event_09ptfxq" /></bpmn:process><bpmndi:BPMNDiagram id="BPMNDiagram_1"><bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_0qbzwnl"><bpmndi:BPMNEdge id="Flow_0udz675_di" bpmnElement="Flow_0udz675"><di:waypoint x="209" y="120" /><di:waypoint x="260" y="120" /></bpmndi:BPMNEdge><bpmndi:BPMNEdge id="Flow_1fwu6d6_di" bpmnElement="Flow_1fwu6d6"><di:waypoint x="360" y="120" /><di:waypoint x="420" y="120" /></bpmndi:BPMNEdge><bpmndi:BPMNEdge id="Flow_0gs9y2g_di" bpmnElement="Flow_0gs9y2g"><di:waypoint x="520" y="120" /><di:waypoint x="582" y="120" /></bpmndi:BPMNEdge><bpmndi:BPMNShape id="StartEvent_1142pjw_di" bpmnElement="StartEvent_1142pjw"><dc:Bounds x="173" y="102" width="36" height="36" /><bpmndi:BPMNLabel><dc:Bounds x="180" y="145" width="22" height="14" /></bpmndi:BPMNLabel></bpmndi:BPMNShape><bpmndi:BPMNShape id="Activity_1umsb7z_di" bpmnElement="Activity_1umsb7z"><dc:Bounds x="260" y="80" width="100" height="80" /></bpmndi:BPMNShape><bpmndi:BPMNShape id="Activity_11qrnub_di" bpmnElement="Activity_11qrnub"><dc:Bounds x="420" y="80" width="100" height="80" /></bpmndi:BPMNShape><bpmndi:BPMNShape id="Event_09ptfxq_di" bpmnElement="Event_09ptfxq"><dc:Bounds x="582" y="102" width="36" height="36" /><bpmndi:BPMNLabel><dc:Bounds x="589" y="145" width="22" height="14" /></bpmndi:BPMNLabel></bpmndi:BPMNShape></bpmndi:BPMNPlane></bpmndi:BPMNDiagram></bpmn:definitions>`, // 效果图中的模板};},methods: {handleSave() {console.log(this.bpmnTemplate, "模板");this.bpmnModeler.saveXML({format: true }, (err, xml) => {if (!err) {console.log(xml);}});},handleBack() {this.$emit("changePage");},newDiagram() {this.createNewDiagram(this.bpmnTemplate);},downloadBpmn() {this.bpmnModeler.saveXML({format: true }, (err, xml) => {if (!err) {// 获取文件名console.log(xml);const name = `${this.getFilename(xml)}.bpmn`;// 将文件名以及数据交给下载方法this.download({name: name, data: xml });}});},downloadSvg() {this.bpmnModeler.saveXML({format: true }, (err, xml) => {if (!err) {// 获取文件名const name = `${this.getFilename(xml)}.svg`;// 从建模器画布中提取svg图形标签let context = "";const djsGroupAll = this.$refs.canvas.querySelectorAll(".djs-group");for (let item of djsGroupAll) {context += item.innerHTML;}// 获取svg的基本数据,长宽高const viewport = this.$refs.canvas.querySelector(".viewport").getBBox();// 将标签和数据拼接成一个完整正常的svg图形const svg = `<svgxmlns="/2000/svg"xmlns:xlink="/1999/xlink"width="${viewport.width}"height="${viewport.height}"viewBox="${viewport.x} ${viewport.y} ${viewport.width} ${viewport.height}"version="1.1">${context}</svg>`;// 将文件名以及数据交给下载方法this.download({name: name, data: svg });}});},openBpmn(file) {const reader = new FileReader();// 读取File对象中的文本信息,编码格式为UTF-8reader.readAsText(file, "utf-8");reader.onload = () => {//读取完毕后将文本信息导入到Bpmn建模器this.createNewDiagram(reader.result);};return false;},getFilename(xml) {let start = xml.indexOf("process");let filename = xml.substr(start, xml.indexOf(">"));filename = filename.substr(filename.indexOf("id") + 4);filename = filename.substr(0, filename.indexOf('"'));return filename;},download({name = "diagram.bpmn", data }) {// 这里就获取到了之前设置的隐藏链接const downloadLink = this.$refs.downloadLink;// 把输就转换为URI,下载要用到的const encodedData = encodeURIComponent(data);if (data) {// 将数据给到链接downloadLink.href ="data:application/bpmn20-xml;charset=UTF-8," + encodedData;// 设置文件名downloadLink.download = name;// 触发点击事件开始下载downloadLink.click();}},async init() {const customTranslateModule = {translate: ["value", customTranslate],};// 获取画布 elementthis.canvas = this.$refs.canvas;// 创建Bpmn对象this.bpmnModeler = new BpmnModeler({// 设置bpmn的绘图容器为上门获取的画布 elementcontainer: this.canvas,additionalModules: [CustomContextPad,CustomPalette,customTranslateModule,],});await this.createNewDiagram(this.bpmnTemplate);},async createNewDiagram(bpmn) {// 将字符串转换成图显示出来;this.bpmnModeler.importXML(bpmn, (err) => {if (err) {this.$message.error("打开模型出错,请确认该模型符合Bpmn2.0规范");}});},},mounted() {this.init();},};</script><style lang="scss" scoped>.topBack {// text-align: right;}.bpmn-canvas {width: 100%;height: calc(100vh - 120px);}.container {// position: relative;.action {position: absolute;bottom: 10px;left: 10px;display: flex;}}.upload-demo {margin-right: 10px;}.bpmn-js-properties-panel {position: absolute;top: 0;right: 0px;width: 300px;}::v-deep .bjs-powered-by {display: none;}.designer {background: #f5f5f5;}::v-deep .djs-palette {left: 0;}</style>

CustomTranslate.js汉化js文件

// BPMN汉化import translations from './TranslationsChinese'export default function customTranslate (template, replacements) {replacements = replacements || {};// Translatetemplate = translations[template] || template;// Replacereturn template.replace(/{([^}]+)}/g, function (_, key) {return replacements[key] || '{' + key + '}';});}

TranslationsChinese.js 汉化的核心配置文件

export default {// Labels'Activate the global connect tool': '激活全局连接工具','Append {type}': '添加 {type}','Add Lane above': '在上面添加道','Divide into two Lanes': '分割成两个道','Divide into three Lanes': '分割成三个道','Add Lane below': '在下面添加道','Append compensation activity': '追加补偿活动','Change type': '修改类型','Connect using Association': '使用关联连接','Connect using Sequence/MessageFlow or Association': '使用顺序/消息流或者关联连接','Connect using DataInputAssociation': '使用数据输入关联连接',Remove: '移除','Activate the hand tool': '激活抓手工具','Activate the lasso tool': '激活套索工具','Activate the create/remove space tool': '激活创建/删除空间工具','Create expanded SubProcess': '创建扩展子过程','Create IntermediateThrowEvent/BoundaryEvent': '创建中间抛出事件/边界事件','Create Pool/Participant': '创建池/参与者','Parallel Multi Instance': '并行多重事件','Sequential Multi Instance': '时序多重事件',DataObjectReference: '数据对象参考',DataStoreReference: '数据存储参考',Loop: '循环','Ad-hoc': '即席','Create {type}': '创建 {type}',Task: '任务','Send Task': '发送任务','Receive Task': '接收任务','User Task': '用户任务','Manual Task': '手工任务','Business Rule Task': '业务规则任务','Service Task': '服务任务','Script Task': '脚本任务','Call Activity': '调用活动','Sub Process (collapsed)': '子流程(折叠的)','Sub Process (expanded)': '子流程(展开的)','Start Event': '开始事件',StartEvent: '开始事件','Intermediate Throw Event': '中间事件','End Event': '结束事件',EndEvent: '结束事件','Create Gateway': '创建网关','Create Intermediate/Boundary Event': '创建中间/边界事件','Message Start Event': '消息开始事件','Timer Start Event': '定时开始事件','Conditional Start Event': '条件开始事件','Signal Start Event': '信号开始事件','Error Start Event': '错误开始事件','Escalation Start Event': '升级开始事件','Compensation Start Event': '补偿开始事件','Message Start Event (non-interrupting)': '消息开始事件(非中断)','Timer Start Event (non-interrupting)': '定时开始事件(非中断)','Conditional Start Event (non-interrupting)': '条件开始事件(非中断)','Signal Start Event (non-interrupting)': '信号开始事件(非中断)','Escalation Start Event (non-interrupting)': '升级开始事件(非中断)','Message Intermediate Catch Event': '消息中间捕获事件','Message Intermediate Throw Event': '消息中间抛出事件','Timer Intermediate Catch Event': '定时中间捕获事件','Escalation Intermediate Throw Event': '升级中间抛出事件','Conditional Intermediate Catch Event': '条件中间捕获事件','Link Intermediate Catch Event': '链接中间捕获事件','Link Intermediate Throw Event': '链接中间抛出事件','Compensation Intermediate Throw Event': '补偿中间抛出事件','Signal Intermediate Catch Event': '信号中间捕获事件','Signal Intermediate Throw Event': '信号中间抛出事件','Message End Event': '消息结束事件','Escalation End Event': '定时结束事件','Error End Event': '错误结束事件','Cancel End Event': '取消结束事件','Compensation End Event': '补偿结束事件','Signal End Event': '信号结束事件','Terminate End Event': '终止结束事件','Message Boundary Event': '消息边界事件','Message Boundary Event (non-interrupting)': '消息边界事件(非中断)','Timer Boundary Event': '定时边界事件','Timer Boundary Event (non-interrupting)': '定时边界事件(非中断)','Escalation Boundary Event': '升级边界事件','Escalation Boundary Event (non-interrupting)': '升级边界事件(非中断)','Conditional Boundary Event': '条件边界事件','Conditional Boundary Event (non-interrupting)': '条件边界事件(非中断)','Error Boundary Event': '错误边界事件','Cancel Boundary Event': '取消边界事件','Signal Boundary Event': '信号边界事件','Signal Boundary Event (non-interrupting)': '信号边界事件(非中断)','Compensation Boundary Event': '补偿边界事件','Exclusive Gateway': '互斥网关','Parallel Gateway': '并行网关','Inclusive Gateway': '相容网关','Complex Gateway': '复杂网关','Event based Gateway': '事件网关',Transaction: '转运','Sub Process': '子流程','Event Sub Process': '事件子流程','Collapsed Pool': '折叠池','Expanded Pool': '展开池',// Errors'no parent for {element} in {parent}': '在{parent}里,{element}没有父类','no shape type specified': '没有指定的形状类型','flow elements must be children of pools/participants': '流元素必须是池/参与者的子类','out of bounds release': 'out of bounds release','more than {count} child lanes': '子道大于{count} ','element required': '元素不能为空','diagram not part of bpmn:Definitions': '流程图不符合bpmn规范','no diagram to display': '没有可展示的流程图','no process or collaboration to display': '没有可展示的流程/协作','element {element} referenced by {referenced}#{property} not yet drawn':'由{referenced}#{property}引用的{element}元素仍未绘制','already rendered {element}': '{element} 已被渲染','failed to import {element}': '导入{element}失败',// 属性面板的参数Id: '编号',Name: '名称',General: '常规',Details: '详情','Message Name': '消息名称',Message: '消息',Initiator: '创建者','Asynchronous Continuations': '持续异步','Asynchronous Before': '异步前','Asynchronous After': '异步后','Job Configuration': '工作配置',Exclusive: '排除','Job Priority': '工作优先级','Retry Time Cycle': '重试时间周期',Documentation: '文档','Element Documentation': '元素文档','History Configuration': '历史配置','History Time To Live': '历史的生存时间',Forms: '表单','Form Key': '表单key','Form Fields': '表单字段','Business Key': '业务key','Form Field': '表单字段',ID: '编号',Type: '类型',Label: '名称','Default Value': '默认值',Validation: '校验','Add Constraint': '添加约束',Config: '配置',Properties: '属性','Add Property': '添加属性',Value: '值',Listeners: '监听器','Execution Listener': '执行监听','Event Type': '事件类型','Listener Type': '监听器类型','Java Class': 'Java类',Expression: '表达式','Must provide a value': '必须提供一个值','Delegate Expression': '代理表达式',Script: '脚本','Script Format': '脚本格式','Script Type': '脚本类型','Inline Script': '内联脚本','External Script': '外部脚本',Resource: '资源','Field Injection': '字段注入',Extensions: '扩展','Input/Output': '输入/输出','Input Parameters': '输入参数','Output Parameters': '输出参数',Parameters: '参数','Output Parameter': '输出参数','Timer Definition Type': '定时器定义类型','Timer Definition': '定时器定义',Date: '日期',Duration: '持续',Cycle: '循环',Signal: '信号','Signal Name': '信号名称',Escalation: '升级',Error: '错误','Link Name': '链接名称',Condition: '条件名称','Variable Name': '变量名称','Variable Event': '变量事件','Specify more than one variable change event as a comma separated list.':'多个变量事件以逗号隔开','Wait for Completion': '等待完成','Activity Ref': '活动参考','Version Tag': '版本标签',Executable: '可执行文件','External Task Configuration': '扩展任务配置','Task Priority': '任务优先级',External: '外部',Connector: '连接器','Must configure Connector': '必须配置连接器','Connector Id': '连接器编号',Implementation: '实现方式','Field Injections': '字段注入',Fields: '字段','Result Variable': '结果变量',Topic: '主题','Configure Connector': '配置连接器','Input Parameter': '输入参数',Assignee: '代理人','Candidate Users': '候选用户','Candidate Groups': '候选组','Due Date': '到期时间','Follow Up Date': '跟踪日期','Specify more than one group as a comma separated list.': '多个用户使用逗号隔开',Priority: '优先级',// eslint-disable-next-line no-template-curly-in-string'The follow up date as an EL expression (e.g. ${someDate} or an ISO date (e.g. -06-26T09:54:00)':'跟踪日期必须符合EL表达式,如: ${someDate} ,或者一个ISO标准日期,如:-06-26T09:54:00',// eslint-disable-next-line no-template-curly-in-string'The due date as an EL expression (e.g. ${someDate} or an ISO date (e.g. -06-26T09:54:00)':'跟踪日期必须符合EL表达式,如: ${someDate} ,或者一个ISO标准日期,如:-06-26T09:54:00',Variables: '变量','Candidate Starter Users': '选择启动候选人','Candidate Starter Configuration': '候选人启动器配置','Candidate Starter Groups': '候选人启动组','This maps to the process definition key.': '编号将映射到流程主键.',save: '保存',Tools: '工具',FlowGateway: '流程网关',ProcessControl: '流程节点','Create StartEvent': '开始节点','Create EndEvent': '结束节点','Create ExclusiveGateway': '互斥网关','Create ParallelGateway': '并行网关','Create Task': '任务节点','Create UserTask': '用户任务节点','Condition Type': '条件类型',// 左侧工具箱补充汉化项'Create Group': '创建组','Create DataObjectReference': '创建数据对象引用','Create DataStoreReference': '创建数据存储引用',// 节点添加Pad'Append EndEvent': '追加结束事件节点','Append Gateway': '追加网关节点','Append Task': '追加任务节点','Append UserTask': '追加用户任务节点','Append Intermediate/Boundary Event': '追加中间或边界事件','Append TextAnnotation': '追加文本批注' // 此句要有效,必须在CustomContexPadProvide给此节点增加一个translate('Append TextAnnotation')}

CustomContextPad.js 右侧context-pad文件

import CustomContextPad from './ContextPadProvider'export default {__init__: ['contextPadProvider'],contextPadProvider: ['type', CustomContextPad]}

ContextPadProvider.js context-pad的配置文件

import {assign,isArray,every,forEach} from 'min-dash'import {is} from 'bpmn-js/lib/util/ModelUtil'import {hasPrimaryModifier} from 'diagram-js/lib/util/Mouse'import {isEventSubProcess} from 'bpmn-js/lib/util/DiUtil';/*** A provider for BPMN 2.0 elements context pad*/export default function ContextPadProvider (config, injector, eventBus,contextPad, modeling, elementFactory,connect, create, popupMenu,canvas, rules, translate) {config = config || {}contextPad.registerProvider(this)this._contextPad = contextPadthis._modeling = modelingthis._elementFactory = elementFactorythis._connect = connectthis._create = createthis._popupMenu = popupMenuthis._canvas = canvasthis._rules = rulesthis._translate = translateif (config.autoPlace !== false) {this._autoPlace = injector.get('autoPlace', false)}eventBus.on('create.end', 250, function (event) {// eslint-disable-next-line one-varvar context = event.context,shape = context.shapeif (!hasPrimaryModifier(event) || !contextPad.isOpen(shape)) {return}var entries = contextPad.getEntries(shape)if (entries.replace) {entries.replace.action.click(event, shape)}})}ContextPadProvider.$inject = ['config.contextPad','injector','eventBus','contextPad','modeling','elementFactory','connect','create','popupMenu','canvas','rules','translate']ContextPadProvider.prototype.getMultiElementContextPadEntries = function (elements) {var modeling = this._modelingvar actions = {}if (this._isDeleteAllowed(elements)) {assign(actions, {'delete': {group: 'edit',className: 'bpmn-icon-trash',title: this._translate('Remove'),action: {click: function (event, elements) {modeling.removeElements(elements.slice())}}}})}return actions}/*** @param {djs.model.Base[]} elements* @return {boolean}*/ContextPadProvider.prototype._isDeleteAllowed = function (elements) {var baseAllowed = this._rules.allowed('elements.delete', {elements: elements})if (isArray(baseAllowed)) {return every(baseAllowed, function (element) {return includes(baseAllowed, element)})}return baseAllowed}ContextPadProvider.prototype.getContextPadEntries = function (element) {// eslint-disable-next-line one-varvar modeling = this._modeling,elementFactory = this._elementFactory,connect = this._connect,create = this._create,rules = this._rules,autoPlace = this._autoPlace,translate = this._translatevar actions = {}if (element.type === 'label') {return actions}var businessObject = element.businessObjectfunction startConnect (event, element) {connect.start(event, element)}function removeElement (e, element) {modeling.removeElements([element])}/*** Create an append action** @param {string} type* @param {string} className* @param {string} [title]* @param {Object} [options]** @return {Object} descriptor*/function appendAction (type, className, title, options) {if (typeof title !== 'string') {options = titletitle = translate('Append {type}', {type: type.replace(/^bpmn:/, '') })}function appendStart (event, element) {var shape = elementFactory.createShape(assign({type: type }, options))create.start(event, shape, {source: element})}var append = autoPlace ? function (event, element) {var shape = elementFactory.createShape(assign({type: type }, options))autoPlace.append(element, shape)} : appendStartreturn {group: 'model',className: className,title: title,action: {dragstart: appendStart,click: append}}}if (is(businessObject, 'bpmn:StartEvent')) {assign(actions, {'append.end-event': appendAction('bpmn:EndEvent', 'bpmn-icon-end-event-none'),// 'append.user-task': appendAction('bpmn:UserTask', 'bpmn-icon-user-task'),'append.gateway': appendAction('bpmn:ExclusiveGateway','bpmn-icon-gateway-none',translate('Append Gateway')),'connect': {group: 'connect',className: 'bpmn-icon-connection-multi',title: translate('Connect using Association'),action: {click: startConnect,dragstart: startConnect}}})}// if (is(businessObject, 'bpmn:UserTask')) {// assign(actions, {//'append.end-event': appendAction('bpmn:EndEvent', 'bpmn-icon-end-event-none'),//'append.user-task': appendAction('bpmn:UserTask', 'bpmn-icon-user-task'),//'append.gateway': appendAction(// 'bpmn:ExclusiveGateway',// 'bpmn-icon-gateway-none',// translate('Append Gateway')//),//'connect': {// group: 'connect',// className: 'bpmn-icon-connection-multi',// title: translate('Connect using Association'),// action: {// click: startConnect,// dragstart: startConnect// }//}// })// }if (is(businessObject, 'bpmn:ExclusiveGateway')) {assign(actions, {'append.end-event': appendAction('bpmn:EndEvent', 'bpmn-icon-end-event-none'),'append.user-task': appendAction('bpmn:UserTask', 'bpmn-icon-user-task'),'append.gateway': appendAction('bpmn:ExclusiveGateway','bpmn-icon-gateway-none',translate('Append Gateway')),'connect': {group: 'connect',className: 'bpmn-icon-connection-multi',title: translate('Connect using Association'),action: {click: startConnect,dragstart: startConnect}}})}if (isEventType(businessObject, 'bpmn:BoundaryEvent', 'bpmn:CompensateEventDefinition')) {assign(actions, {'pensation-activity':appendAction('bpmn:Task','bpmn-icon-task',translate('Append compensation activity'),{isForCompensation: true})});} else if (!is(businessObject, 'bpmn:EndEvent') &&!businessObject.isForCompensation &&!isEventType(businessObject, 'bpmn:IntermediateThrowEvent', 'bpmn:LinkEventDefinition') &&!isEventSubProcess(businessObject)) {assign(actions, {'append.end-event': appendAction('bpmn:EndEvent','bpmn-icon-end-event-none',translate('Append EndEvent')),'append.gateway': appendAction('bpmn:ExclusiveGateway','bpmn-icon-gateway-none',translate('Append Gateway')),'append.append-task': appendAction('bpmn:Task','bpmn-icon-task',translate('Append Task')),'append.intermediate-event': appendAction('bpmn:IntermediateThrowEvent','bpmn-icon-intermediate-event-none',translate('Append Intermediate/Boundary Event')),'connect': {group: 'connect',className: 'bpmn-icon-connection-multi',title: translate('Connect using DataInputAssociation'),action: {click: startConnect,dragstart: startConnect}}})}// delete element entry, only show if allowed by rulesvar deleteAllowed = rules.allowed('elements.delete', {elements: [element] })if (isArray(deleteAllowed)) {// was the element returned as a deletion candidate?deleteAllowed = deleteAllowed[0] === element}if (deleteAllowed) {assign(actions, {'delete': {group: 'edit',className: 'bpmn-icon-trash',title: translate('Remove'),action: {click: removeElement}}})}return actions}function includes (array, item) {return array.indexOf(item) !== -1}// helpers /function isEventType (eventBo, type, definition) {var isType = eventBo.$instanceOf(type);var isDefinition = false;var definitions = eventBo.eventDefinitions || [];forEach(definitions, function (def) {if (def.$type === definition) {isDefinition = true;}});return isType && isDefinition;}

CustomPalette.js 自定义左侧工具栏js’文件

import PaletteProvider from './PaletteProvider'export default {__init__: ['paletteProvider'],paletteProvider: ['type', PaletteProvider]}

PaletteProvider.js 左侧工具栏的核心文件

import {assign} from 'min-dash';/*** A palette provider for BPMN 2.0 elements.*/export default function PaletteProvider(palette, create, elementFactory,spaceTool, lassoTool, handTool,globalConnect, translate) {this._palette = palette;this._create = create;this._elementFactory = elementFactory;this._spaceTool = spaceTool;this._lassoTool = lassoTool;this._handTool = handTool;this._globalConnect = globalConnect;this._translate = translate;palette.registerProvider(this);}PaletteProvider.$inject = ['palette','create','elementFactory','spaceTool','lassoTool','handTool','globalConnect','translate'];PaletteProvider.prototype.getPaletteEntries = function(element) {var actions = {},create = this._create,elementFactory = this._elementFactory,spaceTool = this._spaceTool,lassoTool = this._lassoTool,handTool = this._handTool,globalConnect = this._globalConnect,translate = this._translate;function createAction(type, group, className, title, options) {function createListener(event) {var shape = elementFactory.createShape(assign({type: type }, options));if (options) {shape.businessObject.di.isExpanded = options.isExpanded;}create.start(event, shape);}var shortType = type.replace(/^bpmn:/, '');return {group: group,className: className,title: title || translate('Create {type}', {type: shortType }),action: {dragstart: createListener,click: createListener}};}function createSubprocess(event) {var subProcess = elementFactory.createShape({type: 'bpmn:SubProcess',x: 0,y: 0,isExpanded: true});var startEvent = elementFactory.createShape({type: 'bpmn:StartEvent',x: 40,y: 82,parent: subProcess});create.start(event, [ subProcess, startEvent ], {hints: {autoSelect: [ startEvent ]}});}function createParticipant(event) {create.start(event, elementFactory.createParticipantShape());}function dragEventFactory (type) {return function (event) {const taskShape = elementFactory.create('shape', {type: type});create.start(event, taskShape);};}assign(actions, {'hand-tool': {group: 'tools',className: 'bpmn-icon-hand-tool',title: translate('Activate the hand tool'),action: {click: function(event) {handTool.activateHand(event);}}},'lasso-tool': {group: 'tools',className: 'bpmn-icon-lasso-tool',title: translate('Activate the lasso tool'),action: {click: function(event) {lassoTool.activateSelection(event);}}},'space-tool': {group: 'tools',className: 'bpmn-icon-space-tool',title: translate('Activate the create/remove space tool'),action: {click: function(event) {spaceTool.activateSelection(event);}}},'global-connect-tool': {group: 'tools',className: 'bpmn-icon-connection-multi',title: translate('Activate the global connect tool'),action: {click: function(event) {globalConnect.toggle(event);}}},'tool-separator': {group: 'tools',separator: true},'create.start-event': createAction('bpmn:StartEvent', 'event', 'bpmn-icon-start-event-none',translate('Create StartEvent')),'create.intermediate-event': createAction('bpmn:IntermediateThrowEvent', 'event', 'bpmn-icon-intermediate-event-none',translate('Create Intermediate/Boundary Event')),'create.end-event': createAction('bpmn:EndEvent', 'event', 'bpmn-icon-end-event-none',translate('Create EndEvent')),'create.exclusive-gateway': createAction('bpmn:ExclusiveGateway', 'gateway', 'bpmn-icon-gateway-none',translate('Create Gateway')),'create.task': createAction('bpmn:Task', 'activity', 'bpmn-icon-task',translate('Create Task')),'create.data-object': createAction('bpmn:DataObjectReference', 'data-object', 'bpmn-icon-data-object',translate('Create DataObjectReference')),'create.data-store': createAction('bpmn:DataStoreReference', 'data-store', 'bpmn-icon-data-store',translate('Create DataStoreReference')),'create.subprocess-expanded': {group: 'activity',className: 'bpmn-icon-subprocess-expanded',title: translate('Create expanded SubProcess'),action: {dragstart: createSubprocess,click: createSubprocess}},'create.participant-expanded': {group: 'collaboration',className: 'bpmn-icon-participant',title: translate('Create Pool/Participant'),action: {dragstart: createParticipant,click: createParticipant}},'create.group': createAction('bpmn:Group', 'artifact', 'bpmn-icon-group',translate('Create Group')),'create.cake': {title: '我是自定义节点-呵呵', // 鼠标悬浮到节点上显示的文字className: 'icon-custom bpmn-icon-cake', // 样式名action: {// 操作该节点时会触发的事件,此时只注册一个拖动事件即可,否则拖动时没有效果dragstart: dragEventFactory('bpmn:Task')}},});return actions;};

10.自定义左侧工具栏

自定义做的工具栏的样式必须写在全局css文件中

.bpmn-icon-cake {background-image: url('../logo/logo.png');}.icon-custom {background-size: 65%;background-repeat: no-repeat;background-position: center center;}

PropertiesView.vue中

<template><div class="custom-properties-panel my-card"><div class="empty" v-if="selectedElements.length <= 0">请选择一个节点</div><div class="empty" v-else-if="selectedElements.length > 1">只能选择一个节点</div><div v-else><!-- <fieldset class="element-item"><label>id</label><span>{{element.id }}</span></fieldset><fieldset class="element-item"><label>name</label><input:value="element.name"@change="(event) => changeField(event, 'name')"/></fieldset><fieldset class="element-item"><label>customProps</label><input:value="element.name"@change="(event) => changeField(event, 'customProps')"/></fieldset> --><el-form:model="dataForm":rules="rules"ref="dataForm"label-width="140px"><el-row><el-col :span="24"><el-form-item label="名称" prop="name"><el-input v-model="dataForm.name" placeholder="请输入名称" /></el-form-item></el-col><el-col :span="24"><el-form-item label="节点最大审批人数" prop="code"><el-selectv-model="dataForm.approvalNum"placeholder="请选择节点最大审批人数"style="width: 100%"><el-optionv-for="item in approvalNum":key="item.id":label="item.label":value="item.id"></el-option></el-select></el-form-item></el-col><el-col :span="24"><el-form-item label="审批类型" prop="code"><el-selectv-model="dataForm.approvalType"placeholder="请选择审批类型"style="width: 100%"><el-optionv-for="item in approvalType":key="item.id":label="item.label":value="item.id"></el-option></el-select></el-form-item></el-col><el-col:span="24"v-if="dataForm.approvalType == 1 || dataForm.approvalType == 2"><el-form-item label="已选人员" prop="code"><el-input v-model="dataForm.code" placeholder="请输入编码" /></el-form-item></el-col></el-row></el-form></div></div></template><script>export default {name: "PropertiesView",props: {modeler: {type: Object,default: () => ({}),},},data() {return {selectedElements: [],element: null,approvalNum: [{id: 1,label: "1",},{id: 2,label: "全部",},],approvalType: [{id: 1,label: "指定人员",},{id: 2,label: "指定角色",},{id: 3,label: "由上一步指定",},],dataForm: {id: null,deptType: null,name: null,platforms: [],},rules: {platforms: [{required: true, message: "所属平台不能为空", trigger: "change" },],code: [{required: true, message: "编码不能为空", trigger: "blur" }],name: [{required: true, message: "名称不能为空", trigger: "blur" }],},};},created() {this.init();},methods: {// 因此功能还未写完,流程图跟右侧panel的联动功能逻辑还未实现,在这里可以实现init() {const {modeler } = this;// 右侧面板改变事件modeler.on("selection.changed", (e) => {this.selectedElements = e.newSelection;this.element = e.newSelection[0]?.businessObject;console.log(this.element, "e.newSelection");});modeler.on("element.changed", (e) => {const {element } = e;const {element: currentElement } = this;if (!currentElement) {return;}// 如果当前选择的元素改变,需要同步更新面板if (element.id === currentElement.id) {this.element = element;}});},/*** 改变控件触发的事件* @param { Object } input的Event* @param { String } 要修改的属性的名称*/changeField(event, type) {const value = event.target.value;let properties = {};properties[type] = value;this.element[type] = value;this.updateProperties(properties);},updateName(name) {const {modeler, element } = this;const modeling = modeler.get("modeling");// modeling.updateLabel(element, name)modeling.updateProperties(element, {name,});},/*** 更新元素属性* @param { Object } 要更新的属性, 例如 { name: '' }*/updateProperties(properties) {const {modeler, element } = this;const modeling = modeler.get("modeling");modeling.updateProperties(element, properties);},},};</script><style scoped>.custom-properties-panel {position: absolute;right: 10px;top: 80px;width: 400px;border-color: #ffffff;padding: 20px 10px;}</style>

三、注意

node_modules中有bpmn-js中有左侧工具栏和panel的源码,可以复制出来改造后进行覆盖他本身的一些功能

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。