当前位置:   article > 正文

VUE+bpmn.js实现工作流_vue 引入工作流

vue 引入工作流

1、安装bpmn.js

  1. npm install bpmn-js@7.3.1 // 我安装的版本是7.3.1
  2. npm install bpmn-js-properties-panel@0.37.2
  3. npm install bpmn-moddle@7.1.3
  4. npm install --save camunda-bpmn-moddle

2、配置axios,在main.js中引入axios

  1. import axios from 'axios'
  2. Vue.prototype.$http = axios

3、bpmn汉化,创建defaultXmlStr.js(是初始化的xml文件)、customTranslate.js和translations.js文件,可从网上下载,也可自行新建,目录如下

defaultXmlStr.js内容如下,若将 <startEvent id="StartEvent" name="开始" />去掉,则初始化的页面是空白页

  1. export var defaultXmlStr = `xml <?xml version="1.0" encoding="UTF-8"?>
  2. <definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:camunda="http://camunda.org/schema/1.0/bpmn" id="sid-38422fae-e03e-43a3-bef4-bd33b32041b2" targetNamespace="http://bpmn.io/bpmn" exporter="bpmn-js (https://demo.bpmn.io)" exporterVersion="5.1.2">
  3. <process id="Process" name="默认模板" isExecutable="true" camunda:versionTag="0.0.1">
  4. <startEvent id="StartEvent" name="开始" />
  5. </process>
  6. <bpmndi:BPMNDiagram id="BpmnDiagram_1">
  7. <bpmndi:BPMNPlane id="BpmnPlane_1" bpmnElement="Process">
  8. <bpmndi:BPMNShape id="StartEvent_1y45yut_di" bpmnElement="StartEvent">
  9. <omgdc:Bounds x="152" y="102" width="36" height="36" />
  10. <bpmndi:BPMNLabel>
  11. <omgdc:Bounds x="160" y="145" width="22" height="14" />
  12. </bpmndi:BPMNLabel>
  13. </bpmndi:BPMNShape>
  14. </bpmndi:BPMNPlane>
  15. </bpmndi:BPMNDiagram>
  16. </definitions>`

translations.js内容如下:

  1. /**
  2. * This is a sample file that should be replaced with the actual translation.
  3. *
  4. * Checkout https://github.com/bpmn-io/bpmn-js-i18n for a list of available
  5. * translations and labels to translate.
  6. */
  7. export default {
  8. 'Activate the global connect tool': '激活全局连接工具',
  9. 'Append {type}': '添加 {type}',
  10. 'Add Lane above': '在上面添加道',
  11. 'Divide into two Lanes': '分割成两个道',
  12. 'Divide into three Lanes': '分割成三个道',
  13. 'Add Lane below': '在下面添加道',
  14. 'Append compensation activity': '追加补偿活动',
  15. 'Change type': '修改类型',
  16. 'Connect using Association': '使用关联连接',
  17. 'Connect using Sequence/MessageFlow or Association': '使用顺序/消息流或者关联连接',
  18. 'Connect using DataInputAssociation': '使用数据输入关联连接',
  19. Remove: '移除',
  20. 'Activate the hand tool': '激活抓手工具',
  21. 'Activate the lasso tool': '激活套索工具',
  22. 'Activate the create/remove space tool': '激活创建/删除空间工具',
  23. 'Create expanded SubProcess': '创建扩展子过程',
  24. 'Create IntermediateThrowEvent/BoundaryEvent': '创建中间抛出事件/边界事件',
  25. 'Create Pool/Participant': '创建池/参与者',
  26. 'Parallel Multi Instance': '并行多重事件',
  27. 'Sequential Multi Instance': '时序多重事件',
  28. DataObjectReference: '数据对象参考',
  29. DataStoreReference: '数据存储参考',
  30. Loop: '循环',
  31. 'Ad-hoc': '即席',
  32. 'Create {type}': '创建 {type}',
  33. Task: '任务',
  34. 'Send Task': '发送任务',
  35. 'Receive Task': '接收任务',
  36. 'User Task': '用户任务',
  37. 'Manual Task': '手工任务',
  38. 'Business Rule Task': '业务规则任务',
  39. 'Service Task': '服务任务',
  40. 'Script Task': '脚本任务',
  41. 'Call Activity': '调用活动',
  42. 'Sub Process (collapsed)': '子流程(折叠的)',
  43. 'Sub Process (expanded)': '子流程(展开的)',
  44. 'Start Event': '开始事件',
  45. StartEvent: '开始事件',
  46. 'Intermediate Throw Event': '中间事件',
  47. 'End Event': '结束事件',
  48. EndEvent: '结束事件',
  49. 'Create Gateway': '创建网关',
  50. 'Create Intermediate/Boundary Event': '创建中间/边界事件',
  51. 'Message Start Event': '消息开始事件',
  52. 'Timer Start Event': '定时开始事件',
  53. 'Conditional Start Event': '条件开始事件',
  54. 'Signal Start Event': '信号开始事件',
  55. 'Error Start Event': '错误开始事件',
  56. 'Escalation Start Event': '升级开始事件',
  57. 'Compensation Start Event': '补偿开始事件',
  58. 'Message Start Event (non-interrupting)': '消息开始事件(非中断)',
  59. 'Timer Start Event (non-interrupting)': '定时开始事件(非中断)',
  60. 'Conditional Start Event (non-interrupting)': '条件开始事件(非中断)',
  61. 'Signal Start Event (non-interrupting)': '信号开始事件(非中断)',
  62. 'Escalation Start Event (non-interrupting)': '升级开始事件(非中断)',
  63. 'Message Intermediate Catch Event': '消息中间捕获事件',
  64. 'Message Intermediate Throw Event': '消息中间抛出事件',
  65. 'Timer Intermediate Catch Event': '定时中间捕获事件',
  66. 'Escalation Intermediate Throw Event': '升级中间抛出事件',
  67. 'Conditional Intermediate Catch Event': '条件中间捕获事件',
  68. 'Link Intermediate Catch Event': '链接中间捕获事件',
  69. 'Link Intermediate Throw Event': '链接中间抛出事件',
  70. 'Compensation Intermediate Throw Event': '补偿中间抛出事件',
  71. 'Signal Intermediate Catch Event': '信号中间捕获事件',
  72. 'Signal Intermediate Throw Event': '信号中间抛出事件',
  73. 'Message End Event': '消息结束事件',
  74. 'Escalation End Event': '定时结束事件',
  75. 'Error End Event': '错误结束事件',
  76. 'Cancel End Event': '取消结束事件',
  77. 'Compensation End Event': '补偿结束事件',
  78. 'Signal End Event': '信号结束事件',
  79. 'Terminate End Event': '终止结束事件',
  80. 'Message Boundary Event': '消息边界事件',
  81. 'Message Boundary Event (non-interrupting)': '消息边界事件(非中断)',
  82. 'Timer Boundary Event': '定时边界事件',
  83. 'Timer Boundary Event (non-interrupting)': '定时边界事件(非中断)',
  84. 'Escalation Boundary Event': '升级边界事件',
  85. 'Escalation Boundary Event (non-interrupting)': '升级边界事件(非中断)',
  86. 'Conditional Boundary Event': '条件边界事件',
  87. 'Conditional Boundary Event (non-interrupting)': '条件边界事件(非中断)',
  88. 'Error Boundary Event': '错误边界事件',
  89. 'Cancel Boundary Event': '取消边界事件',
  90. 'Signal Boundary Event': '信号边界事件',
  91. 'Signal Boundary Event (non-interrupting)': '信号边界事件(非中断)',
  92. 'Compensation Boundary Event': '补偿边界事件',
  93. 'Exclusive Gateway': '互斥网关',
  94. 'Parallel Gateway': '并行网关',
  95. 'Inclusive Gateway': '相容网关',
  96. 'Complex Gateway': '复杂网关',
  97. 'Event based Gateway': '事件网关',
  98. Transaction: '转运',
  99. 'Sub Process': '子流程',
  100. 'Event Sub Process': '事件子流程',
  101. 'Collapsed Pool': '折叠池',
  102. 'Expanded Pool': '展开池',
  103. // Errors
  104. 'no parent for {element} in {parent}': '在{parent}里,{element}没有父类',
  105. 'no shape type specified': '没有指定的形状类型',
  106. 'flow elements must be children of pools/participants': '流元素必须是池/参与者的子类',
  107. 'out of bounds release': '越界释放',
  108. 'more than {count} child lanes': '子道大于{count} ',
  109. 'element required': '元素不能为空',
  110. 'diagram not part of bpmn:Definitions': '流程图不符合bpmn规范',
  111. 'no diagram to display': '没有可展示的流程图',
  112. 'no process or collaboration to display': '没有可展示的流程/协作',
  113. 'element {element} referenced by {referenced}#{property} not yet drawn': '由{referenced}#{property}引用的{element}元素仍未绘制',
  114. 'already rendered {element}': '{element} 已被渲染',
  115. 'failed to import {element}': '导入{element}失败',
  116. // 属性面板的参数
  117. Id: 'KEY',
  118. Name: '名称',
  119. General: '常规',
  120. Details: '详情',
  121. 'Message Name': '消息名称',
  122. Message: '消息',
  123. Initiator: '创建者',
  124. 'Asynchronous Continuations': '持续异步',
  125. 'Asynchronous Before': '异步前',
  126. 'Asynchronous After': '异步后',
  127. 'Job Configuration': '工作配置',
  128. Exclusive: '排除',
  129. 'Job Priority': '工作优先级',
  130. 'Retry Time Cycle': '重试时间周期',
  131. Documentation: '文档',
  132. 'Element Documentation': '元素文档',
  133. 'History Configuration': '历史配置',
  134. 'History Time To Live': '历史的生存时间',
  135. Forms: '表单',
  136. 'Form Key': '表单key',
  137. 'Form Fields': '表单字段',
  138. 'Business Key': '业务key',
  139. 'Form Field': '表单字段',
  140. ID: '编号',
  141. Type: '类型',
  142. Label: '名称',
  143. 'Default Value': '默认值',
  144. Validation: '校验',
  145. 'Add Constraint': '添加约束',
  146. Config: '配置',
  147. Properties: '属性',
  148. 'Add Property': '添加属性',
  149. Value: '值',
  150. Listeners: '监听器',
  151. 'Execution Listener': '执行监听',
  152. 'Event Type': '事件类型',
  153. 'Listener Type': '监听器类型',
  154. 'Java Class': 'Java类',
  155. Expression: '表达式',
  156. 'Must provide a value': '必须提供一个值',
  157. 'Delegate Expression': '代理表达式',
  158. Script: '脚本',
  159. 'Script Format': '脚本格式',
  160. 'Script Type': '脚本类型',
  161. 'Inline Script': '内联脚本',
  162. 'External Script': '外部脚本',
  163. Resource: '资源',
  164. 'Field Injection': '字段注入',
  165. Extensions: '扩展',
  166. 'Input/Output': '输入/输出',
  167. 'Input Parameters': '输入参数',
  168. 'Output Parameters': '输出参数',
  169. Parameters: '参数',
  170. 'Output Parameter': '输出参数',
  171. 'Timer Definition Type': '定时器定义类型',
  172. 'Timer Definition': '定时器定义',
  173. Date: '日期',
  174. Duration: '持续',
  175. Cycle: '循环',
  176. Signal: '信号',
  177. 'Signal Name': '信号名称',
  178. Escalation: '升级',
  179. Error: '错误',
  180. 'Link Name': '链接名称',
  181. Condition: '条件名称',
  182. 'Variable Name': '变量名称',
  183. 'Variable Event': '变量事件',
  184. 'Specify more than one variable change event as a comma separated list.': '多个变量事件以逗号隔开',
  185. 'Wait for Completion': '等待完成',
  186. 'Activity Ref': '活动参考',
  187. 'Version Tag': '版本标签',
  188. Executable: '可执行文件',
  189. 'External Task Configuration': '扩展任务配置',
  190. 'Task Priority': '任务优先级',
  191. External: '外部',
  192. Connector: '连接器',
  193. 'Must configure Connector': '必须配置连接器',
  194. 'Connector Id': '连接器编号',
  195. Implementation: '实现方式',
  196. 'Field Injections': '字段注入',
  197. Fields: '字段',
  198. 'Result Variable': '结果变量',
  199. Topic: '主题',
  200. 'Configure Connector': '配置连接器',
  201. 'Input Parameter': '输入参数',
  202. Assignee: '代理人',
  203. 'Candidate Users': '候选用户',
  204. 'Candidate Groups': '候选组',
  205. 'Due Date': '到期时间',
  206. 'Follow Up Date': '跟踪日期',
  207. Priority: '优先级',
  208. Variables: '变量',
  209. 'This maps to the process definition key.': '同时会映射为流程定义Key',
  210. 'Element must have an unique id.': '元素必须有唯一的Key',
  211. 'Id must be a valid QName.': 'Key不合法',
  212. 'Candidate Starter Configuration': '候选人起动器配置',
  213. 'Candidate Starter Groups': '候选人起动器组',
  214. 'Specify more than one group as a comma separated list.': '多个组使用英文逗号隔开',
  215. 'Candidate Starter Users': '允许发起流程的用户ID',
  216. 'Specify more than one user as a comma separated list.': '多个用户使用英文逗号隔开',
  217. 'Tasklist Configuration': '任务列表配置',
  218. Startable: '可启动',
  219. 'Available process variables, identified in the diagram.': '在流程图中指定的变量',
  220. 'No variables found.': '没有发现变量',
  221. 'This maps to the task definition key.': '映射到任务定义键',
  222. 'No variables defined.': '没有定义变量',
  223. 'The follow up date as an EL expression (e.g. ${someDate} or an ISO date (e.g. 2015-06-26T09:54:00)':
  224. '跟踪日期必须符合EL表达式,如: ${someDate} ,或者一个ISO标准日期,如:2015-06-26T09:54:00',
  225. 'The due date as an EL expression (e.g. ${someDate} or an ISO date (e.g. 2015-06-26T09:54:00)':
  226. '跟踪日期必须符合EL表达式,如: ${someDate} ,或者一个ISO标准日期,如:2015-06-26T09:54:00',
  227. }

customTranslate.js内容如下:

  1. import translations from './translations'
  2. export default function customTranslate(template, replacements) {
  3. replacements = replacements || {}
  4. // Translate
  5. template = translations[template] || template
  6. // Replace
  7. return template.replace(/{([^}]+)}/g, function (_, key) {
  8. return replacements[key] || '{' + key + '}'
  9. })
  10. }

3、构建一个简单的vue页面

  1. <template>
  2. <div class="containers" ref="content">
  3. <a-space>
  4. <el-button @click="downloadBpmn">
  5. <a-icon type="download" />
  6. 保存BPMN
  7. </el-button>
  8. <el-button @click="downloadSvg">
  9. <a-icon type="download" />
  10. 保存SVG
  11. </el-button>
  12. <a-upload :file-list="uploadBpmnFileList" :before-upload="beforeUpload">
  13. <el-button>
  14. <a-icon type="upload" />
  15. 导入BPMN
  16. </el-button>
  17. </a-upload>
  18. <el-button-group>
  19. <el-button @click="handlerUndo">撤销</el-button>
  20. <el-button @click="handlerRedo">恢复</el-button>
  21. </el-button-group>
  22. <el-button-group>
  23. <el-button @click="handlerZoom(0.1)">放大</el-button>
  24. <el-button @click="handlerZoom(-0.1)">缩小</el-button>
  25. <el-button @click="handlerZoom(0)">还原</el-button>
  26. </el-button-group>
  27. <a hidden ref="downloadLink"></a>
  28. </a-space>
  29. <div class="canvas" ref="canvas"></div>
  30. <div id="js-properties-panel" class="panel"></div>
  31. </div>
  32. </template>
  33. <script>
  34. import BpmnModeler from 'bpmn-js/lib/Modeler'
  35. import propertiesPanelModule from 'bpmn-js-properties-panel'
  36. import propertiesProviderModule from 'bpmn-js-properties-panel/lib/provider/bpmn'
  37. import bpmnModdleDescriptor from 'bpmn-moddle/resources/bpmn/json/bpmn.json'
  38. // BPMN国际化
  39. import customTranslate from './customTranslate/customTranslate'
  40. import { defaultXmlStr } from './defaultXmlStr'
  41. // 自定义汉化模块
  42. var customTranslateModule = {
  43. translate: ['value', customTranslate],
  44. }
  45. export default {
  46. components: {},
  47. data() {
  48. return {
  49. bpmnModeler: null,
  50. container: null,
  51. canvas: null,
  52. uploadBpmnFileList: [],
  53. scale: 1,
  54. }
  55. },
  56. created() {},
  57. mounted() {
  58. this.init()
  59. },
  60. methods: {
  61. /**
  62. * 初始化流程设计器对象
  63. * @returns {Promise<void>}
  64. */
  65. async init() {
  66. // xmlStr 是现有的图,defaultXmlStr是默认只有开始的图
  67. this.xmlStr = await this.getXmlUrl()
  68. this.$nextTick(() => {
  69. this.initBpmn()
  70. })
  71. },
  72. async initBpmn() {
  73. // 获取到属性ref为“content”的dom节点
  74. this.container = this.$refs.content
  75. // 获取到属性ref为“canvas”的dom节点
  76. const canvas = this.$refs.canvas
  77. // 创建BpmnModeler
  78. this.bpmnModeler = new BpmnModeler({
  79. container: canvas,
  80. // 加入工具栏支持
  81. propertiesPanel: {
  82. parent: '#js-properties-panel',
  83. },
  84. additionalModules: [
  85. // 左边工具栏以及节点
  86. propertiesProviderModule,
  87. // 右边的工具栏
  88. propertiesPanelModule,
  89. // 国际化
  90. customTranslateModule,
  91. ],
  92. moddleExtensions: {
  93. bpmn: bpmnModdleDescriptor,
  94. },
  95. })
  96. // 创建新流程
  97. await this.createNewDiagram(defaultXmlStr)
  98. },
  99. getXmlUrl() {
  100. let diagramUrl = 'https://hexo-blog-1256114407.cos.ap-shenzhen-fsi.myqcloud.com/mock1.bpmn'
  101. return new Promise(resolve => {
  102. this.$http.get(diagramUrl).then(function (res) {
  103. resolve(res.data)
  104. })
  105. })
  106. },
  107. /**
  108. * 创建新流程
  109. * @param bpmn BPMN流程XML报文
  110. * @returns {Promise<void>}
  111. */
  112. async createNewDiagram(bpmn) {
  113. // 将字符串转换成图显示出来;
  114. this.bpmnModeler.importXML(bpmn, err => {
  115. if (err) {
  116. this.$message.error('打开模型出错,请确认该模型符合Bpmn2.0规范')
  117. } else {
  118. console.log('成功导入模型')
  119. }
  120. })
  121. },
  122. handlerRedo() {
  123. this.bpmnModeler.get('commandStack').redo()
  124. },
  125. handlerUndo() {
  126. this.bpmnModeler.get('commandStack').undo()
  127. },
  128. handlerZoom(radio) {
  129. const newScale = !radio ? 1.0 : this.scale + radio
  130. this.bpmnModeler.get('canvas').zoom(newScale)
  131. this.scale = newScale
  132. },
  133. beforeUpload(file) {
  134. // this.uploadBpmnFileList = [];
  135. this.openBpmn(file)
  136. return false
  137. },
  138. openBpmn(file) {
  139. const reader = new FileReader()
  140. // 读取File对象中的文本信息,编码格式为UTF-8
  141. reader.readAsText(file, 'utf-8')
  142. reader.onload = () => {
  143. // 读取完毕后将文本信息导入到Bpmn建模器
  144. this.createNewDiagram(reader.result)
  145. }
  146. return false
  147. },
  148. downloadBpmn() {
  149. this.bpmnModeler.saveXML({ format: true }, (err, xml) => {
  150. if (!err) {
  151. // 获取文件名
  152. const name = `${this.getFilename(xml)}.bpmn`
  153. // 将文件名以及数据交给下载方法
  154. this.download({ name: name, data: xml })
  155. }
  156. })
  157. },
  158. downloadSvg() {
  159. this.bpmnModeler.saveXML({ format: true }, (err, xml) => {
  160. if (!err) {
  161. // 获取文件名
  162. const name = `${this.getFilename(xml)}.svg`
  163. // 从建模器画布中提取svg图形标签
  164. let context = ''
  165. const djsGroupAll = this.$refs.canvas.querySelectorAll('.djs-group')
  166. for (let item of djsGroupAll) {
  167. context += item.innerHTML
  168. }
  169. // 获取svg的基本数据,长宽高
  170. const viewport = this.$refs.canvas.querySelector('.viewport').getBBox()
  171. // 将标签和数据拼接成一个完整正常的svg图形
  172. const svg = `
  173. <svg
  174. xmlns="http://www.w3.org/2000/svg"
  175. xmlns:xlink="http://www.w3.org/1999/xlink"
  176. width="${viewport.width}"
  177. height="${viewport.height}"
  178. viewBox="${viewport.x} ${viewport.y} ${viewport.width} ${viewport.height}"
  179. version="1.1"
  180. >
  181. ${context}
  182. </svg>
  183. `
  184. // 将文件名以及数据交给下载方法
  185. this.download({ name: name, data: svg })
  186. }
  187. })
  188. },
  189. download({ name = 'diagram.bpmn', data }) {
  190. // 这里就获取到了之前设置的隐藏链接
  191. const downloadLink = this.$refs.downloadLink
  192. // 把输就转换为URI,下载要用到的
  193. const encodedData = encodeURIComponent(data)
  194. if (data) {
  195. // 将数据给到链接
  196. downloadLink.href = 'data:application/bpmn20-xml;charset=UTF-8,' + encodedData
  197. // 设置文件名
  198. downloadLink.download = name
  199. // 触发点击事件开始下载
  200. downloadLink.click()
  201. }
  202. },
  203. getFilename(xml) {
  204. let start = xml.indexOf('process')
  205. let filename = xml.substr(start, xml.indexOf('>'))
  206. filename = filename.substr(filename.indexOf('id') + 4)
  207. filename = filename.substr(0, filename.indexOf('"'))
  208. return filename
  209. },
  210. },
  211. computed: {},
  212. }
  213. </script>
  214. <style lang="less" scoped>
  215. // 左边工具栏以及编辑节点的样式
  216. @import '~bpmn-js/dist/assets/diagram-js.css';
  217. @import '~bpmn-js/dist/assets/bpmn-font/css/bpmn.css';
  218. @import '~bpmn-js/dist/assets/bpmn-font/css/bpmn-codes.css';
  219. @import '~bpmn-js/dist/assets/bpmn-font/css/bpmn-embedded.css';
  220. // 右边工具栏样式
  221. @import '~bpmn-js-properties-panel/dist/assets/bpmn-js-properties-panel.css';
  222. .containers {
  223. position: absolute;
  224. background-color: #ffffff;
  225. width: 80%;
  226. height: 100vh;
  227. padding: 5px;
  228. }
  229. .canvas {
  230. width: 100%;
  231. height: 100%;
  232. }
  233. .panel {
  234. position: absolute;
  235. right: 0;
  236. top: 0;
  237. width: 300px;
  238. }
  239. </style>

结果如下:

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/852299
推荐阅读
  

闽ICP备14008679号