參考連結
Vue 整合Bpmn-js 工作流模型編輯器 - 掘金
bpmn-js快速上手及漢化_<每天一點>的部落格-CSDN部落格_bpmn-js
//先提前安裝好cnpm
xnpm 設定淘寶鏡像、nrm、nodemon - 走看看
// 建立一個Vue項目
vue create demo
//vue必須選擇2的版本,否則報錯
// 安裝一下項目依賴,
cnpm npm install
//安裝bpmn 後面記得改版本
cnpm install bpmn-js
cnpm install bpmn-js-properties-panel
cnpm install camunda-bpmn-moddle
cnpm install element-ui
//打開package.json,下面的版本必須按照這個來,否則報錯
"dependencies": {
"bpmn-js": "^7.3.1",
"bpmn-js-properties-panel": "^0.37.2",
"camunda-bpmn-moddle": "^4.4.0",
"core-js": "^3.8.3",
"element-ui": "^2.15.10",
"vue": "^2.6.14"
}
//删除node_modules
//然後重新安裝依賴
cnpm install
在src目錄下建立customTranslate.js和translations.js
//建立customTranslate.js 内容如下
import translations from './translations'
export default function customTranslate(template, replacements) {
replacements = replacements || {}
// Translate
template = translations[template] || template
// Replace
return template.replace(/{([^}]+)}/g, function(_, key) {
return replacements[key] || '{' + key + '}'
})
}
//建立translations.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': '跟蹤日期',
'Priority': '優先級',
// 'The follow up date as an EL expression (e.g. ${someDate} or an ISO date (e.g. 2015-06-26T09:54:00)': '跟蹤日期必須符合EL表達式,如: ${someDate} ,或者一個ISO标準日期,如:2015-06-26T09:54:00',
// 'The due date as an EL expression (e.g. ${someDate} or an ISO date (e.g. 2015-06-26T09:54:00)': '跟蹤日期必須符合EL表達式,如: ${someDate} ,或者一個ISO标準日期,如:2015-06-26T09:54:00',
'Variables': '變量'
}
//在App.vue直接替換,内容如下
<template>
<div id="app">
<div class="container">
<!-- 建立一個canvas畫布 npmn-js是通過canvas實作繪圖的,并設定ref讓vue擷取到element -->
<div class="bpmn-canvas" ref="canvas"></div>
<!-- 工具欄顯示的地方 -->
<div class="bpmn-js-properties-panel" id="js-properties-panel"></div>
<!-- 把操作按鈕寫在這裡面 -->
<div class="action">
<el-upload action class="upload-demo" :before-upload="openBpmn">
<el-button icon="el-icon-folder-opened"></el-button>
</el-upload>
<el-button class="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 propertiesProviderModule from "bpmn-js-properties-panel/lib/provider/camunda";
import propertiesPanelModule from "bpmn-js-properties-panel";
import camundaModdleDescriptor from "camunda-bpmn-moddle/resources/camunda";
//漢化
import customTranslate from './customTranslate'
export default {
data() {
return {
bpmnModeler: null,
canvas: null,
bpmnTemplate: `
<?xml version="1.0" encoding="UTF-8"?>
<definitions
xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI"
xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC"
xmlns:camunda="http://camunda.org/schema/1.0/bpmn"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:activiti="http://activiti.org/bpmn"
id="m1577635100724"
name=""
targetNamespace="http://www.activiti.org/testm1577635100724"
>
<process id="process" processType="None" isClosed="false" isExecutable="true">
<extensionElements>
<camunda:properties>
<camunda:property name="a" value="1" />
</camunda:properties>
</extensionElements>
<startEvent id="_2" name="start" />
</process>
<bpmndi:BPMNDiagram id="BPMNDiagram_leave">
<bpmndi:BPMNPlane id="BPMNPlane_leave" bpmnElement="leave">
<bpmndi:BPMNShape id="BPMNShape__2" bpmnElement="_2">
<omgdc:Bounds x="144" y="368" width="32" height="32" />
<bpmndi:BPMNLabel>
<omgdc:Bounds x="149" y="400" width="23" height="14" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</definitions>
`
};
},
methods: {
newDiagram() {
this.createNewDiagram(this.bpmnTemplate);
},
downloadBpmn() {
this.bpmnModeler.saveXML({ format: true }, (err, xml) => {
if (!err) {
// 擷取檔案名
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 = `
<svg
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/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-8
reader.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() {
// 擷取畫布 element
this.canvas = this.$refs.canvas;
//将漢化包裝成一個子產品
var customTranslateModule = {
translate: [ 'value', customTranslate ]
}
// 建立Bpmn對象
this.bpmnModeler = new BpmnModeler({
// 設定bpmn的繪圖容器為上門擷取的畫布 element
container: this.canvas,
// 加入工具欄支援
propertiesPanel: {
parent: "#js-properties-panel"
},
additionalModules: [
propertiesProviderModule,
propertiesPanelModule,
//漢化子產品
customTranslateModule
],
moddleExtensions: {
camunda: camundaModdleDescriptor
}
});
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>
.bpmn-canvas {
width: 100%;
height: 100vh;
}
.action {
position: fixed;
bottom: 10px;
left: 10px;
display: flex;
}
.upload-demo {
margin-right: 10px;
}
.bpmn-js-properties-panel {
position: absolute;
top: 0;
right: 0px;
width: 300px;
}
</style>
//在main.js直接替換,内容如下
import Vue from 'vue'
import App from './App.vue'
//import router from './router'
// 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'
// 左邊工具欄以及編輯節點的樣式
import 'bpmn-js-properties-panel/dist/assets/bpmn-js-properties-panel.css'
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
Vue.use(ElementUI);
Vue.config.productionTip = false
new Vue({
// router,
render: h => h(App)
}).$mount('#app')
//然後啟動項目
npm run serve
//浏覽器打開位址,下面就是內建好的界面了
http://localhost:8080/
接下來我們做下線上部署xml
安裝
npm install axios --save
在main.js中寫入一下代碼
import axios from 'axios'
Vue.prototype.axios = axios
在第18行代碼加入這一句
<el-button @click="deploy">線上部署</el-button>
在第81行代碼下加入
deploy() {
this.bpmnModeler.saveXML({ format: true }, (err, xml) => {
if (!err) {
// 擷取檔案名
const name = `${this.getFilename(xml)}.bpmn`;
//xml的内容
console.log(xml);
//調用後端接口 線上部署
this.axios({
url: 'http://localhost:8080/deployXml',//請求位址
method:'POST',//請求方法
responseType: 'json',//傳回值類型
params: {
"name": name,
"xml": xml
}
}).then(res => {
console.log(res)//請求成功
}).catch(error => {
console.log(error);//請求失敗
})
}
});
},
在看下後端代碼
/**
* 流程定義控制層
*/
@RestController
public class ProcessDefinitionController {
@Autowired
private RepositoryService repositoryService;
/**
* 部署xml
*/
@PostMapping(value = "deployXml")
public String deployXml(@RequestParam("name")String name,@RequestParam("xml") String xml) throws IOException {
Deployment deploy = repositoryService.createDeployment()
//name必須以xxx.bpmn結尾
.addInputStream(name+".bpmn",new ByteArrayInputStream(xml.getBytes()))
.name(name)
.deploy();
return deploy.getId();
}
}
可以看到xml就是控制台列印的資料
點選線上部署
這3張表就插入資料了