mirror of
https://gitee.com/huangge1199_admin/vue-pro.git
synced 2024-11-26 09:11:52 +08:00
fix: 增加流程图前端代码
This commit is contained in:
parent
00f59fdc75
commit
3f90e79d8a
@ -43,8 +43,8 @@ public class ModelController {
|
||||
|
||||
@GetMapping ("/page")
|
||||
@ApiOperation(value = "分页数据")
|
||||
public PageResult<Model> pageList(ModelPageReqVo modelPageReqVo) {
|
||||
return bpmModelService.pageList(modelPageReqVo);
|
||||
public CommonResult<PageResult<Model>> pageList(ModelPageReqVo modelPageReqVo) {
|
||||
return CommonResult.success(bpmModelService.pageList(modelPageReqVo));
|
||||
}
|
||||
|
||||
@PostMapping("/create")
|
||||
|
@ -40,7 +40,8 @@
|
||||
"@riophae/vue-treeselect": "0.4.0",
|
||||
"axios": "0.21.0",
|
||||
"clipboard": "2.0.6",
|
||||
"core-js": "3.8.1",
|
||||
"core-js": "3.19.1",
|
||||
"jeeplus-bpmn": "^6.0.10",
|
||||
"echarts": "4.9.0",
|
||||
"element-ui": "2.15.0",
|
||||
"file-saver": "2.0.4",
|
||||
@ -75,7 +76,8 @@
|
||||
"sass-loader": "10.1.0",
|
||||
"script-ext-html-webpack-plugin": "2.1.5",
|
||||
"svg-sprite-loader": "5.1.1",
|
||||
"vue-template-compiler": "2.6.12"
|
||||
"vue-template-compiler": "2.6.12",
|
||||
"vue2-ace-editor": "^0.0.15"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.9",
|
||||
|
10
yudao-admin-ui/src/api/bpm/model.js
Normal file
10
yudao-admin-ui/src/api/bpm/model.js
Normal file
@ -0,0 +1,10 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
|
||||
export function page(query) {
|
||||
return request({
|
||||
url: '/workflow/models/page',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
139
yudao-admin-ui/src/components/bpmn/Header.vue
Normal file
139
yudao-admin-ui/src/components/bpmn/Header.vue
Normal file
@ -0,0 +1,139 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-button-group>
|
||||
<el-tooltip class="item" effect="dark" content="保存并发布" placement="bottom">
|
||||
<el-button type="primary" size="small" @click="deploy"><i class="fa fa-save"> 保存并发布</i></el-button>
|
||||
</el-tooltip>
|
||||
<el-tooltip class="item" effect="dark" content="保存草稿" placement="bottom">
|
||||
<el-button type="primary" size="small" @click="save"><i class="fa fa-save"> 保存草稿</i></el-button>
|
||||
</el-tooltip>
|
||||
<el-tooltip class="item" effect="dark" content="打开流程文件" placement="bottom">
|
||||
<el-button type="primary" size="small" @click="importXml"><i class="fa fa-folder-open"></i></el-button>
|
||||
</el-tooltip>
|
||||
<el-tooltip class="item" effect="dark" content="创建新流程图" placement="bottom">
|
||||
<el-button type="primary" size="small" @click="reset"><i class="fa fa-plus-circle"></i></el-button>
|
||||
</el-tooltip>
|
||||
<el-tooltip class="item" effect="dark" content="下载流程图" placement="bottom">
|
||||
<el-button type="primary" size="small" @click="downloadSvg"><i class="fa fa-picture-o"></i></el-button>
|
||||
</el-tooltip>
|
||||
<el-tooltip class="item" effect="dark" content="下载流程文件" placement="bottom">
|
||||
<el-button type="primary" size="small" @click="downloadBpmn"><i class="fa fa-download"></i></el-button>
|
||||
</el-tooltip>
|
||||
<el-tooltip class="item" effect="dark" content="撤销" placement="bottom">
|
||||
<el-button size="small"><i class="fa fa-rotate-left" @click="undo"></i></el-button>
|
||||
</el-tooltip>
|
||||
<el-tooltip class="item" effect="dark" content="恢复" placement="bottom">
|
||||
<el-button size="small"><i class="fa fa-rotate-right" :class="!canRedo?'default-undo':''"
|
||||
@click="redo"></i></el-button>
|
||||
</el-tooltip>
|
||||
<el-tooltip class="item" effect="dark" content="放大" placement="bottom">
|
||||
<el-button size="small" @click="zoom(0.05)"><i class="fa fa-search-plus"></i></el-button>
|
||||
</el-tooltip>
|
||||
<el-tooltip class="item" effect="dark" content="缩小" placement="bottom">
|
||||
<el-button size="small" @click="zoom(-0.05)"><i class="fa fa-search-minus"></i></el-button>
|
||||
</el-tooltip>
|
||||
<el-tooltip class="item" effect="dark" content="重置" placement="bottom">
|
||||
<el-button size="small" @click="zoom(0)"><i class="fa fa-arrows"></i></el-button>
|
||||
</el-tooltip>
|
||||
</el-button-group>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "ViewerHeader",
|
||||
data() {
|
||||
return {
|
||||
scale: 1.0,
|
||||
canRedo: false
|
||||
}
|
||||
},
|
||||
props: {
|
||||
processData: {
|
||||
type: Object
|
||||
},
|
||||
modeler: {
|
||||
type: Object
|
||||
}
|
||||
},
|
||||
components: {},
|
||||
methods: {
|
||||
deploy() {
|
||||
let that = this;
|
||||
let _xml;
|
||||
let _svg;
|
||||
this.modeler.saveXML((err, xml) => {
|
||||
if (err) {
|
||||
console.error(err)
|
||||
}
|
||||
_xml = xml;
|
||||
})
|
||||
this.modeler.saveSVG((err, svg) => {
|
||||
if (err) {
|
||||
console.error(err)
|
||||
}
|
||||
_svg = svg;
|
||||
})
|
||||
that.post(this.Apis.deployProcess, {
|
||||
processKey: "s1111",
|
||||
processName: "阿达达",
|
||||
resourceName: "test01",
|
||||
xml: _xml,
|
||||
svg: _svg
|
||||
}, function (data) {
|
||||
console.log(data)
|
||||
});
|
||||
},
|
||||
save(){
|
||||
let that = this;
|
||||
let _xml;
|
||||
let _svg;
|
||||
this.modeler.saveXML((err, xml) => {
|
||||
if (err) {
|
||||
console.error(err)
|
||||
}
|
||||
_xml = xml;
|
||||
})
|
||||
this.modeler.saveSVG((err, svg) => {
|
||||
if (err) {
|
||||
console.error(err)
|
||||
}
|
||||
_svg = svg;
|
||||
})
|
||||
that.$emit("processSave",{"xmlStr":_xml,"svgStr":_svg});
|
||||
},
|
||||
reset() {
|
||||
this.$emit('restart')
|
||||
},
|
||||
importXml() {
|
||||
this.$emit('importXml')
|
||||
},
|
||||
downloadSvg() {
|
||||
this.$emit("handleExportSvg")
|
||||
},
|
||||
downloadBpmn() {
|
||||
this.$emit("handleExportBpmn");
|
||||
},
|
||||
undo() {
|
||||
this.modeler.get('commandStack').undo();
|
||||
this.canRedo = this.modeler.get('commandStack').canRedo();
|
||||
},
|
||||
redo() {
|
||||
if (!this.canRedo) {
|
||||
return;
|
||||
}
|
||||
this.modeler.get('commandStack').redo()
|
||||
this.canRedo = this.modeler.get('commandStack').canRedo();
|
||||
},
|
||||
zoom(val) {
|
||||
let newScale = !val ? 1.0 : ((this.scale + val) <= 0.2) ? 0.2 : (this.scale + val);
|
||||
this.modeler.get('canvas').zoom(newScale);
|
||||
this.scale = newScale;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
264
yudao-admin-ui/src/components/bpmn/VueBpmn.vue
Normal file
264
yudao-admin-ui/src/components/bpmn/VueBpmn.vue
Normal file
@ -0,0 +1,264 @@
|
||||
<template>
|
||||
<div class="">
|
||||
<ImportDialog :dialogVisibleBool="importXmlShow" @closeShowXmlDialog="closeShowXmlDialog"></ImportDialog>
|
||||
<el-row>
|
||||
<el-col :span="24">
|
||||
<vue-header class="bpmn-viewer-header" :processData="initData" :modeler="bpmnModeler" @restart="restart" @importXml="importXml"
|
||||
@handleExportSvg="handleExportSvg" @handleExportBpmn="handleExportBpmn" @processSave="processSave"></vue-header>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row style="margin-left: 1%">
|
||||
<el-tabs v-model="activeName" type="card" >
|
||||
<el-tab-pane label="流程设计器" name="first">
|
||||
<el-col :span="19">
|
||||
<div class="bpmn-viewer">
|
||||
<div class="bpmn-viewer-content" ref="bpmnViewer" ></div>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="5">
|
||||
<bpmn-panel style="width: 92%" @updateXml="updateXml" v-if="bpmnModeler" :modeler="bpmnModeler" :process="initData"></bpmn-panel>
|
||||
</el-col>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="流程XML" name="second">
|
||||
<editor v-model="xmlShowWatch" @init="editorInit" lang="xml" theme="chrome" width="98%" height="calc(100vh - 100px)"></editor>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</el-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import templateXml from "./data/template";
|
||||
import ImportDialog from "./dialog/ImportDialog";
|
||||
// import activitiCom from "../provider/activiti";
|
||||
// import BpmnModeler2 from 'bpmn-js/lib/Modeler';
|
||||
import BpmnModeler from 'jeeplus-bpmn/lib/Modeler'
|
||||
import customTranslate from "./data/translate/customTranslate";
|
||||
import VueHeader from "./Header";
|
||||
import BpmnPanel from "./panel/index";
|
||||
import activitiModule from './data/activiti.json'
|
||||
import flowableModule from './data/flowable.json'
|
||||
import './assets/css/vue-bmpn.css'
|
||||
import './assets/css/font-awesome.min.css'
|
||||
|
||||
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 './assets/css/vue-bmpn.css'
|
||||
export default {
|
||||
name: "VueBpmn",
|
||||
data() {
|
||||
return {
|
||||
bpmnModeler: null,
|
||||
importXmlShow: false,
|
||||
xmlShowWatch: "",
|
||||
initTemplate: "",
|
||||
activeName: "first",
|
||||
initData: {},
|
||||
xmlShow: ""
|
||||
}
|
||||
},
|
||||
props: {
|
||||
product: String,
|
||||
bpmnXml: {
|
||||
type: String,
|
||||
required: false
|
||||
}
|
||||
},
|
||||
components: {
|
||||
editor: require('vue2-ace-editor'),
|
||||
VueHeader, BpmnPanel,ImportDialog
|
||||
},
|
||||
watch: {
|
||||
xmlShow: {
|
||||
handler(){
|
||||
this.xmlShowWatch = this.xmlShow
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
let processId = new Date().getTime();
|
||||
this.initTemplate = templateXml.initTemplate(processId)
|
||||
this.initData = {key: "process" + processId, name: "流程" + processId, xml: this.initTemplate}
|
||||
if (this.bpmnXml != null) {
|
||||
this.initTemplate = this.bpmnXml
|
||||
}
|
||||
this.init();
|
||||
},
|
||||
methods: {
|
||||
editorInit: function (editor) {
|
||||
require('brace/mode/xml')
|
||||
require('brace/theme/chrome')
|
||||
editor.setOptions({
|
||||
fontSize: "15px"
|
||||
})
|
||||
editor.getSession().setUseWrapMode(true);
|
||||
},
|
||||
init() {
|
||||
const _this = this;
|
||||
// 支持activiti和flowable
|
||||
let _moddleExtensions = this.getModdleExtensions();
|
||||
// 获取画布 element
|
||||
this.canvas = this.$refs.bpmnViewer;
|
||||
// 创建Bpmn对象
|
||||
this.bpmnModeler = new BpmnModeler({
|
||||
container: this.canvas,
|
||||
additionalModules: [
|
||||
{
|
||||
translate: ['value', customTranslate]
|
||||
},
|
||||
// activitiCom
|
||||
],
|
||||
moddleExtensions: _moddleExtensions
|
||||
});
|
||||
// 初始化建模器内容
|
||||
this.initDiagram(this.initTemplate);
|
||||
setTimeout(function () {
|
||||
_this.bpmnModeler.saveXML({format: true}, function (err, xml) {
|
||||
_this.updateXml(xml)
|
||||
});
|
||||
// console.log(_this.bpmnModeler);
|
||||
// const elementRegistry = _this.bpmnModeler.get('elementRegistry');
|
||||
// const startEvenList = elementRegistry.filter (
|
||||
// (item) => item.type === 'bpmn:StartEvent'
|
||||
// );
|
||||
// // 初始化 开始节点
|
||||
// _this.bpmnModeler.get("modeling").updateProperties(startEvenList[0], {"activiti:initiator": "applyUserId"});
|
||||
}, 300)
|
||||
|
||||
},
|
||||
initDiagram(xml) {
|
||||
this.bpmnModeler.importXML(xml, err => {
|
||||
if (err) {
|
||||
// this.$Message.error("打开模型出错,请确认该模型符合Bpmn2.0规范");
|
||||
}
|
||||
let _tag = document.getElementsByTagName("svg")[0];
|
||||
if (_tag) {
|
||||
_tag.style.width = "100%";
|
||||
_tag.style.height = "700px";
|
||||
}
|
||||
});
|
||||
|
||||
},
|
||||
handleExportBpmn() {
|
||||
const _this = this;
|
||||
this.bpmnModeler.saveXML(function (err, xml) {
|
||||
if (err) {
|
||||
console.error(err)
|
||||
}
|
||||
let {filename, href} = _this.setEncoded('BPMN', xml);
|
||||
if (href && filename) {
|
||||
let a = document.createElement('a');
|
||||
a.download = filename; //指定下载的文件名
|
||||
a.href = href; // URL对象
|
||||
a.click(); // 模拟点击
|
||||
URL.revokeObjectURL(a.href); // 释放URL 对象
|
||||
}
|
||||
});
|
||||
},
|
||||
updateXml(xmlShow) {
|
||||
this.xmlShow = xmlShow
|
||||
},
|
||||
handleExportSvg() {
|
||||
const _this = this;
|
||||
this.bpmnModeler.saveSVG(function (err, svg) {
|
||||
if (err) {
|
||||
console.error(err)
|
||||
}
|
||||
let {filename, href} = _this.setEncoded('SVG', svg);
|
||||
if (href && filename) {
|
||||
let a = document.createElement('a');
|
||||
a.download = filename;
|
||||
a.href = href;
|
||||
a.click();
|
||||
URL.revokeObjectURL(a.href);
|
||||
}
|
||||
});
|
||||
},
|
||||
setEncoded(type, data) {
|
||||
const encodedData = encodeURIComponent(data);
|
||||
if (data) {
|
||||
if (type === 'XML') {
|
||||
return {
|
||||
filename: 'diagram.bpmn20.xml',
|
||||
href: "data:application/bpmn20-xml;charset=UTF-8," + encodedData,
|
||||
data: data
|
||||
}
|
||||
}
|
||||
if (type === 'BPMN') {
|
||||
return {
|
||||
filename: 'diagram.bpmn',
|
||||
href: "data:application/bpmn20-xml;charset=UTF-8," + encodedData,
|
||||
data: data
|
||||
}
|
||||
}
|
||||
if (type === 'SVG') {
|
||||
this.initData.svg = data;
|
||||
return {
|
||||
filename: 'diagram.svg',
|
||||
href: "data:application/text/xml;charset=UTF-8," + encodedData,
|
||||
data: data
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
processSave(data){
|
||||
let initData = this.initData;
|
||||
data.procId = initData.key;
|
||||
data.name = initData.name;
|
||||
this.$emit("processSave",data);
|
||||
},
|
||||
restart() {
|
||||
let processId = new Date().getTime();
|
||||
this.initTemplate = templateXml.initTemplate(processId)
|
||||
this.initData = {key: "process" + processId, name: "流程" + processId, xml: this.initTemplate}
|
||||
this.initDiagram(this.initTemplate)
|
||||
},
|
||||
importXml() {
|
||||
this.importXmlShow = true
|
||||
},
|
||||
closeShowXmlDialog(xmlData) {
|
||||
this.importXmlShow = false
|
||||
const that =this;
|
||||
if (xmlData != null) {
|
||||
this.initDiagram(xmlData)
|
||||
// 刷新数据
|
||||
setTimeout(function () {
|
||||
that.bpmnModeler.saveXML({format: true}, function (err, xml) {
|
||||
that.updateXml(xml)
|
||||
})
|
||||
},500)
|
||||
}
|
||||
},
|
||||
getModdleExtensions() {
|
||||
let moddleExtensions = {};
|
||||
if (this.product === "flowable") {
|
||||
moddleExtensions = {
|
||||
flowable: flowableModule
|
||||
}
|
||||
}
|
||||
if (this.product === "activiti") {
|
||||
moddleExtensions = {
|
||||
activiti: activitiModule
|
||||
}
|
||||
}
|
||||
return moddleExtensions;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.djs-palette{
|
||||
top: 10px;
|
||||
left: 10px;
|
||||
}
|
||||
/deep/.el-tabs__header{
|
||||
margin: 0;
|
||||
}
|
||||
/deep/.el-tabs--card>.el-tabs__header{
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
</style>
|
4
yudao-admin-ui/src/components/bpmn/assets/css/font-awesome.min.css
vendored
Normal file
4
yudao-admin-ui/src/components/bpmn/assets/css/font-awesome.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
55
yudao-admin-ui/src/components/bpmn/assets/css/vue-bmpn.css
Normal file
55
yudao-admin-ui/src/components/bpmn/assets/css/vue-bmpn.css
Normal file
@ -0,0 +1,55 @@
|
||||
.bjs-powered-by{
|
||||
display: none;
|
||||
}
|
||||
|
||||
.djs-palette.two-column.open{
|
||||
width: 48px;
|
||||
}
|
||||
.container{
|
||||
display: flex;
|
||||
}
|
||||
.bpmn-viewer{
|
||||
flex: 1;
|
||||
}
|
||||
.bpmn-viewer-header{
|
||||
height: 50px;
|
||||
line-height: 50px;
|
||||
padding-left: 20px;
|
||||
background: #f8f8f8;
|
||||
}
|
||||
.bpmn-viewer-container{
|
||||
padding: 10px;
|
||||
height: 100%;
|
||||
}
|
||||
.bpmn-viewer-content{
|
||||
width: 100%;
|
||||
/*height: 100%;*/
|
||||
height: calc(100vh - 150px);
|
||||
overflow-x: hidden;
|
||||
background: url("data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDAiIGhlaWdodD0iNDAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PHBhdHRlcm4gaWQ9ImEiIHdpZHRoPSI0MCIgaGVpZ2h0PSI0MCIgcGF0dGVyblVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHBhdGggZD0iTTAgMTBoNDBNMTAgMHY0ME0wIDIwaDQwTTIwIDB2NDBNMCAzMGg0ME0zMCAwdjQwIiBmaWxsPSJub25lIiBzdHJva2U9IiNlMGUwZTAiIG9wYWNpdHk9Ii4yIi8+PHBhdGggZD0iTTQwIDBIMHY0MCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjZTBlMGUwIi8+PC9wYXR0ZXJuPjwvZGVmcz48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSJ1cmwoI2EpIi8+PC9zdmc+") repeat!important;
|
||||
}
|
||||
.el-collapse-item__header{
|
||||
padding-left: 15px;
|
||||
}
|
||||
.djs-direct-editing-parent{
|
||||
/*display: none;*/
|
||||
}
|
||||
.bpmn-panel {
|
||||
/*width: 370px;*/
|
||||
border: 1px solid #eeeeee;
|
||||
padding: 0 5px;
|
||||
}
|
||||
.el-select--small{
|
||||
width: 100%;
|
||||
}
|
||||
.el-dialog > .el-dialog__header{
|
||||
padding: 5px 20px ;
|
||||
}
|
||||
.el-dialog > .el-dialog__body{
|
||||
padding: 0px;
|
||||
margin: 0 20px;
|
||||
border: 1px solid #cccccc;
|
||||
}
|
||||
.default-undo{
|
||||
color: #c0c4cc;
|
||||
}
|
BIN
yudao-admin-ui/src/components/bpmn/assets/fonts/FontAwesome.otf
Normal file
BIN
yudao-admin-ui/src/components/bpmn/assets/fonts/FontAwesome.otf
Normal file
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load Diff
After Width: | Height: | Size: 434 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
13
yudao-admin-ui/src/components/bpmn/data.json
Normal file
13
yudao-admin-ui/src/components/bpmn/data.json
Normal file
@ -0,0 +1,13 @@
|
||||
{
|
||||
"datalist": {
|
||||
"error": {
|
||||
"type": 1,
|
||||
"number": [
|
||||
1
|
||||
],
|
||||
"list": []
|
||||
},
|
||||
"not": [],
|
||||
"right": []
|
||||
}
|
||||
}
|
20
yudao-admin-ui/src/components/bpmn/data.vue
Normal file
20
yudao-admin-ui/src/components/bpmn/data.vue
Normal file
@ -0,0 +1,20 @@
|
||||
<template>
|
||||
<div>
|
||||
<div v-if="type==1"></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "data",
|
||||
data(){
|
||||
return {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
1151
yudao-admin-ui/src/components/bpmn/data/activiti.json
Normal file
1151
yudao-admin-ui/src/components/bpmn/data/activiti.json
Normal file
File diff suppressed because it is too large
Load Diff
1109
yudao-admin-ui/src/components/bpmn/data/flowable.json
Normal file
1109
yudao-admin-ui/src/components/bpmn/data/flowable.json
Normal file
File diff suppressed because it is too large
Load Diff
22
yudao-admin-ui/src/components/bpmn/data/template.js
Normal file
22
yudao-admin-ui/src/components/bpmn/data/template.js
Normal file
@ -0,0 +1,22 @@
|
||||
let xml = `
|
||||
<bpmn2:definitions xmlns:bpmn2="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:dc="http://www.omg.org/spec/DD/20100524/DC" id="sample-diagram" targetNamespace="http://bpmn.io/schema/bpmn" xsi:schemaLocation="http://www.omg.org/spec/BPMN/20100524/MODEL BPMN20.xsd">
|
||||
<bpmn2:process id="process{str}" name="流程{str}">
|
||||
<bpmn2:startEvent id="StartEvent_01ydzqe" name="开始" activiti:initiator="applyUserId" />
|
||||
</bpmn2:process>
|
||||
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
|
||||
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="process{str}">
|
||||
<bpmndi:BPMNShape id="StartEvent_01ydzqe_di" bpmnElement="StartEvent_01ydzqe">
|
||||
<dc:Bounds x="142" y="212" width="36" height="36" />
|
||||
<bpmndi:BPMNLabel>
|
||||
<dc:Bounds x="149" y="255" width="22" height="14" />
|
||||
</bpmndi:BPMNLabel>
|
||||
</bpmndi:BPMNShape>
|
||||
</bpmndi:BPMNPlane>
|
||||
</bpmndi:BPMNDiagram>
|
||||
</bpmn2:definitions>`;
|
||||
|
||||
export default {
|
||||
initTemplate: function (str) {
|
||||
return xml.replace(/{str}/g, str)
|
||||
}
|
||||
};
|
@ -0,0 +1,12 @@
|
||||
import translations from './zn'
|
||||
export default function customTranslate(template, replacements) {
|
||||
replacements = replacements || {};
|
||||
|
||||
// Translate
|
||||
template = translations[template] || template;
|
||||
|
||||
// Replace
|
||||
return template.replace(/{([^}]+)}/g, function(_, key) {
|
||||
return replacements[key] || '{' + key + '}';
|
||||
});
|
||||
}
|
116
yudao-admin-ui/src/components/bpmn/data/translate/zn.js
Normal file
116
yudao-admin-ui/src/components/bpmn/data/translate/zn.js
Normal file
@ -0,0 +1,116 @@
|
||||
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': '启动 Lasso 工具',
|
||||
'Activate the create/remove space tool': '启动创建/删除空间工具',
|
||||
'Create expanded SubProcess': '创建可折叠子流程',
|
||||
'Create IntermediateThrowEvent/BoundaryEvent': '创建中间抛出/边界事件',
|
||||
'Create Pool/Participant': '创建池/参与者',
|
||||
'Parallel Multi Instance': '并行多实例',
|
||||
'Sequential Multi Instance': '串行多实例',
|
||||
'Loop': '循环',
|
||||
'Ad-hoc': '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': '开始事件',
|
||||
'Intermediate Throw Event': '中间抛出事件',
|
||||
'End 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}': '在 {element} 中没有父元素 {parent}',
|
||||
'no shape type specified': '未指定形状类型',
|
||||
'flow elements must be children of pools/participants': '元素必须是池/参与者的子级',
|
||||
'out of bounds release': '越界释放',
|
||||
'more than {count} child lanes': '超过 {count} 条通道',
|
||||
'element required': '需要元素',
|
||||
'diagram not part of bpmn:Definitions': '图表不是 bpmn:Definitions 的一部分',
|
||||
'no diagram to display': '没有要显示的图表',
|
||||
'no process or collaboration to display': '没有可显示的流程或协作',
|
||||
'element {element} referenced by {referenced}#{property} not yet drawn': '元素 {element} 的引用 {referenced}#{property} 尚未绘制',
|
||||
'already rendered {element}': '{element} 已呈现',
|
||||
'failed to import {element}': '{element} 导入失败',
|
||||
|
||||
'Create StartEvent':'创建开始节点',
|
||||
'Create Intermediate/Boundary Event':'创建中间/边界事件',
|
||||
'Create EndEvent':'创建结束节点',
|
||||
'Create Gateway':'创建网关',
|
||||
'Create Task':'创建任务',
|
||||
'Append ExclusiveGateway':'网关',
|
||||
'Append UserTask':'用户任务',
|
||||
'Append EndEvent':'结束节点'
|
||||
};
|
73
yudao-admin-ui/src/components/bpmn/dialog/ImportDialog.vue
Normal file
73
yudao-admin-ui/src/components/bpmn/dialog/ImportDialog.vue
Normal file
@ -0,0 +1,73 @@
|
||||
<template>
|
||||
<el-dialog title="导入BPMN" :visible.sync="dialogFormVisible" :before-close="close">
|
||||
<el-form>
|
||||
<editor v-model="xmlData" @init="editorInit" lang="xml" theme="chrome" width="98%" height="calc(60vh - 100px)"></editor>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button type="primary" @click="commitForm()">确 定</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
name: "ImportDialog",
|
||||
data() {
|
||||
return {
|
||||
activeNames: ['1'],
|
||||
formLabelWidth: "200px",
|
||||
xmlData: "类",
|
||||
value: "类",
|
||||
options: [
|
||||
{
|
||||
value: "类",
|
||||
label: "类"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
components: {
|
||||
editor: require('vue2-ace-editor'),
|
||||
},
|
||||
props: {
|
||||
dialogVisibleBool:{
|
||||
type: Boolean,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
computed:{
|
||||
dialogFormVisible:{
|
||||
get(){
|
||||
this.xmlData = null
|
||||
return this.dialogVisibleBool
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.xmlData = null
|
||||
},
|
||||
methods: {
|
||||
editorInit: function (editor) {
|
||||
require('brace/mode/xml')
|
||||
require('brace/theme/chrome')
|
||||
editor.setOptions({
|
||||
fontSize: "15px"
|
||||
})
|
||||
editor.getSession().setUseWrapMode(true);
|
||||
},
|
||||
commitForm(){
|
||||
this.$emit('closeShowXmlDialog', this.xmlData);
|
||||
},
|
||||
close(){
|
||||
this.$emit('closeShowXmlDialog', null);
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/deep/.el-dialog > .el-dialog__header{
|
||||
padding: 24px 20px
|
||||
}
|
||||
</style>
|
318
yudao-admin-ui/src/components/bpmn/panel/NodePropertyPanel.vue
Normal file
318
yudao-admin-ui/src/components/bpmn/panel/NodePropertyPanel.vue
Normal file
@ -0,0 +1,318 @@
|
||||
<template>
|
||||
<div>
|
||||
<!-- 流程属性 -->
|
||||
<el-collapse v-model="activeNames" accordion>
|
||||
<el-collapse-item name="1">
|
||||
<template slot="title">
|
||||
<div class="title">
|
||||
<i class="header-icon el-icon-setting"></i>
|
||||
<span>基本设置</span>
|
||||
</div>
|
||||
</template>
|
||||
<div>
|
||||
<el-form label-position="right" label-width="70px">
|
||||
<el-form-item label="节点类型">
|
||||
<el-input v-model="localFormData.type" disabled></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="ID">
|
||||
<el-input v-model="localFormData.id" @input="updateId"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="名称">
|
||||
<el-input v-model="localFormData.name " @input="updateName"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="localFormData.type==='bpmn:SequenceFlow'" label="分支条件">
|
||||
<el-input v-model="localFormData.sequenceFlow" @input="updateSequenceFlow"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</el-collapse-item>
|
||||
|
||||
<el-collapse-item name="2">
|
||||
<template slot="title">
|
||||
<div class="title">
|
||||
<i class="header-icon el-icon-setting"></i>
|
||||
<span>执行监听</span>
|
||||
</div>
|
||||
</template>
|
||||
<div>
|
||||
<div style="margin: 10px 3%;float: right">
|
||||
<el-button size="mini" plain @click="showEventDialogMethod">添加</el-button>
|
||||
</div>
|
||||
<el-table
|
||||
border :data="listenerTable"
|
||||
style="width: 93%;margin: 0 auto">
|
||||
<el-table-column align="center" prop="event"
|
||||
label="事件">
|
||||
</el-table-column>
|
||||
<el-table-column align="center" prop="type" :show-overflow-tooltip="true"
|
||||
label="类型">
|
||||
</el-table-column>
|
||||
<el-table-column align="center" prop="class" :show-overflow-tooltip="true"
|
||||
label="实现">
|
||||
</el-table-column>
|
||||
<el-table-column align="center"
|
||||
label="操作">
|
||||
<template slot-scope="scope">
|
||||
<div>
|
||||
<i class="el-icon-delete" @click="deleteEvent(scope.$index)"></i>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</el-collapse-item>
|
||||
<el-collapse-item name="3" v-if="localFormData.type=='bpmn:UserTask'" >
|
||||
<template slot="title">
|
||||
<div class="title">
|
||||
<i class="header-icon el-icon-setting"></i>
|
||||
<span>权限设置</span>
|
||||
</div>
|
||||
</template>
|
||||
<div>
|
||||
<el-form style="margin-top: 25px" label-position="right" label-width="90px">
|
||||
<el-form-item label="用户类型:">
|
||||
<el-select v-model="localFormData.userType" placeholder="请选择" @change="changeUserType" style="width: 90%">
|
||||
<el-option value="assignee" label="指定人员"></el-option>
|
||||
<el-option value="candidateUsers" label="候选人员"></el-option>
|
||||
<el-option value="candidateGroups" label="角色/岗位"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="指定人员" v-if="localFormData.userType === 'assignee'">
|
||||
<el-input placeholder="请输入内容" v-model="localFormData.assignee" @input="(value) => addUser({assignee: value})" style="width: 90%">
|
||||
<template slot="append">
|
||||
<div class="icon-div">
|
||||
<i class="el-icon-user" @click="showUserDialogMethod" />
|
||||
<!-- <div role="separator" class="ant-divider ant-divider-vertical"></div>-->
|
||||
<!-- <i class="el-icon-c-scale-to-original" />-->
|
||||
</div>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="候选人员" v-else-if="localFormData.userType === 'candidateUsers'">
|
||||
<el-input placeholder="请输入内容" v-model="localFormData.candidateUsers" @input="(value) => addUser({candidateUsers: value})" style="width: 90%">
|
||||
<template slot="append">
|
||||
<div class="icon-div">
|
||||
<i class="el-icon-user" @click="showUserDialogMethod" />
|
||||
<!-- <div role="separator" class="ant-divider ant-divider-vertical"></div>-->
|
||||
<!-- <i class="el-icon-c-scale-to-original" />-->
|
||||
</div>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="角色/岗位" v-else-if="localFormData.userType === 'candidateGroups'">
|
||||
<el-input placeholder="请输入内容" v-model="localFormData.candidateGroups" @input="(value) => addUser({candidateGroups: value})" style="width: 90%">
|
||||
<template slot="append">
|
||||
<div class="icon-div">
|
||||
<i class="el-icon-user" @click="showUserDialogMethod" />
|
||||
<!-- <div role="separator" class="ant-divider ant-divider-vertical"></div>-->
|
||||
<!-- <i class="el-icon-c-scale-to-original" />-->
|
||||
</div>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</el-collapse-item>
|
||||
</el-collapse>
|
||||
<EventListenerDialog @commitEventForm="commitEventForm"
|
||||
:dialogFormVisibleBool="showEventDialog"
|
||||
:formData="eventFormData" :nodeElement="nodeElement" :modeler="modeler" :listenerTable="listenerTable"></EventListenerDialog>
|
||||
<UserSelectDialog @commitUserForm="commitUserForm"
|
||||
:type="localFormData.userType"
|
||||
:dialogFormVisibleBool="showUserDialog"
|
||||
:formData="userFormData"
|
||||
:nodeElement="nodeElement"
|
||||
:modeler="modeler"></UserSelectDialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import EventListenerDialog from "./dialog/EventListenerDialog"
|
||||
import UserSelectDialog from "./dialog/UserSelectDialog"
|
||||
export default {
|
||||
name: "NodePropertyPanel",
|
||||
data() {
|
||||
return {
|
||||
activeNames: ['1'],
|
||||
listenerTable: [],
|
||||
showEventDialog: false,
|
||||
showUserDialog: false,
|
||||
eventFormData: {},
|
||||
userFormData: {}
|
||||
}
|
||||
},
|
||||
components: {
|
||||
EventListenerDialog,UserSelectDialog
|
||||
},
|
||||
props: {
|
||||
modeler: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
nodeElement: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
formData:{
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
computed:{
|
||||
localFormData:{
|
||||
get(){
|
||||
return this.formData
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
const that = this
|
||||
if (this.nodeElement.businessObject
|
||||
&& this.nodeElement.businessObject.extensionElements
|
||||
&& this.nodeElement.businessObject.extensionElements.values) {
|
||||
// 根据xml 组合当前节点的监听数据
|
||||
that.listenerTable = this.nodeElement.businessObject.extensionElements.values.filter(
|
||||
(item) => {
|
||||
if (item.$type === 'activiti:ExecutionListener') {
|
||||
item.type = Object.keys(item)[1]
|
||||
item.class = item[Object.keys(item)[1]]
|
||||
return true;
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
},
|
||||
watch:{
|
||||
nodeElement:{
|
||||
handler(){
|
||||
if(this.nodeElement.type==="bpmn:StartEvent"){
|
||||
this.updateName("开始");
|
||||
}
|
||||
if(this.nodeElement.type==="bpmn:EndEvent"){
|
||||
this.updateName("结束");
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
updateProperties(properties){
|
||||
this.modeler.get("modeling").updateProperties(this.nodeElement, properties);
|
||||
},
|
||||
updateId(name) {
|
||||
this.updateProperties({id: name});
|
||||
},
|
||||
updateName(name) {
|
||||
this.updateProperties({name: name});
|
||||
},
|
||||
changeUserType() {
|
||||
},
|
||||
updateSequenceFlow(val){
|
||||
let newCondition = this.modeler.get("moddle").create('bpmn:FormalExpression', {
|
||||
body: val
|
||||
});
|
||||
this.updateProperties({conditionExpression:newCondition});
|
||||
},
|
||||
addUser(properties){
|
||||
this.updateProperties(properties);
|
||||
Object.assign(properties, {
|
||||
userType: Object.keys(properties)[0]
|
||||
});
|
||||
console.log(properties)
|
||||
this.$emit('modifyFormData',properties);
|
||||
},
|
||||
showEventDialogMethod(){
|
||||
this.showEventDialog = true;
|
||||
this.eventFormData= {
|
||||
event:"start",
|
||||
type:"class"
|
||||
}
|
||||
},
|
||||
showUserDialogMethod(){
|
||||
this.showUserDialog = true;
|
||||
this.eventFormData= {
|
||||
event:"start",
|
||||
type:"class"
|
||||
}
|
||||
},
|
||||
deleteEvent(index){
|
||||
const data = this.listenerTable[index]
|
||||
if (this.nodeElement.businessObject
|
||||
&& this.nodeElement.businessObject.extensionElements
|
||||
&& this.nodeElement.businessObject.extensionElements.values) {
|
||||
// 排除全局监听类型 并且class为删除的class的数据。
|
||||
const filterArr = this.nodeElement.businessObject.extensionElements.values.filter(
|
||||
(item) => !(item.$type === 'activiti:ExecutionListener' && item.event === data.event && data.class === item[data.type])
|
||||
)
|
||||
// 刷新数据
|
||||
let extensionElements = this.modeler.get("bpmnFactory").create("bpmn:ExtensionElements", {values: filterArr});
|
||||
this.modeler.get("modeling").updateProperties(this.nodeElement, {extensionElements});
|
||||
}
|
||||
this.listenerTable.splice(index, 1);
|
||||
},
|
||||
commitEventForm(from){
|
||||
this.showEventDialog = false
|
||||
if (from != null) {
|
||||
// 筛选原来数组里是不是有跟刚提交的数据一模一样的数据
|
||||
this.listenerTable.push(from)
|
||||
}
|
||||
},
|
||||
commitUserForm(from){
|
||||
this.showUserDialog = false
|
||||
if (from != null) {
|
||||
console.log(from)
|
||||
// 筛选原来数组里是不是有跟刚提交的数据一模一样的数据
|
||||
// this.listenerTable.push(from)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.title span{
|
||||
font-weight: bold;
|
||||
margin-left: 5px;
|
||||
}
|
||||
/deep/.el-select .el-input .el-select__caret{
|
||||
margin-top: 5px;
|
||||
}
|
||||
/deep/.el-input__icon{
|
||||
height: 20px !important;
|
||||
line-height: 20px !important;
|
||||
}
|
||||
/deep/.el-input-group__append{
|
||||
padding: 0 5px !important;
|
||||
}
|
||||
.icon-div{
|
||||
font-size: 1.2em;
|
||||
font-weight: bold !important;
|
||||
width: 100%;
|
||||
}
|
||||
.icon-div i{
|
||||
padding: 5px;
|
||||
}
|
||||
.icon-div i:hover{
|
||||
cursor:pointer;
|
||||
}
|
||||
.ant-divider-vertical {
|
||||
position: relative;
|
||||
top: -0.08em;
|
||||
display: inline-block;
|
||||
width: 2px;
|
||||
height: 0.9em;
|
||||
/*margin: 0 8px;*/
|
||||
vertical-align: middle;
|
||||
}
|
||||
.ant-divider {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
color: rgba(0, 0, 0, 0.65);
|
||||
font-size: 14px;
|
||||
font-variant: tabular-nums;
|
||||
line-height: 1.5;
|
||||
list-style: none;
|
||||
/*font-feature-settings: "tnum";*/
|
||||
background: #e8e8e8;
|
||||
}
|
||||
</style>
|
@ -0,0 +1,244 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-collapse v-model="activeNames" accordion>
|
||||
<el-collapse-item name="1">
|
||||
<template slot="title">
|
||||
<div class="title">
|
||||
<i class="header-icon el-icon-setting"></i>
|
||||
<span>基本设置</span>
|
||||
</div>
|
||||
</template>
|
||||
<div>
|
||||
<el-form label-position="right" label-width="70px">
|
||||
<el-form-item label="流程ID">
|
||||
<el-input v-model="localProcessData.key" @input="updateId"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="流程名称">
|
||||
<el-input v-model="localProcessData.name" @input="updateName"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="流程描述">
|
||||
<el-input v-model="localProcessData.description" @input="updateDesc"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</el-collapse-item>
|
||||
<el-collapse-item name="2">
|
||||
<template slot="title">
|
||||
<div class="title">
|
||||
<i class="header-icon el-icon-setting"></i>
|
||||
<span>执行监听</span>
|
||||
</div>
|
||||
</template>
|
||||
<div>
|
||||
<div style="margin: 10px 3%;float: right">
|
||||
<el-button size="mini" plain @click="showEventDialogMethod">添加</el-button>
|
||||
</div>
|
||||
<el-table
|
||||
border :data="listenerTable"
|
||||
style="width: 93%;margin: 0 auto">
|
||||
<el-table-column align="center" prop="event"
|
||||
label="事件">
|
||||
</el-table-column>
|
||||
<el-table-column align="center" prop="type" :show-overflow-tooltip="true"
|
||||
label="类型">
|
||||
</el-table-column>
|
||||
<el-table-column align="center" prop="class" :show-overflow-tooltip="true"
|
||||
label="实现">
|
||||
</el-table-column>
|
||||
<el-table-column align="center"
|
||||
label="操作">
|
||||
<template slot-scope="scope">
|
||||
<div>
|
||||
<i class="el-icon-delete" @click="deleteEvent(scope.$index)"></i>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</el-collapse-item>
|
||||
<el-collapse-item name="3">
|
||||
<template slot="title">
|
||||
<div class="title">
|
||||
<i class="header-icon el-icon-setting"></i>
|
||||
<span>全局监听</span>
|
||||
</div>
|
||||
</template>
|
||||
<div>
|
||||
<div style="margin: 10px 3%;float: right">
|
||||
<el-button size="mini" plain @click="showGlobalDialogMethod">添加</el-button>
|
||||
</div>
|
||||
<el-table
|
||||
border :data="globalFormTable"
|
||||
style="width: 93%;margin: 0 auto">
|
||||
<el-table-column align="center" prop="class" :show-overflow-tooltip="true"
|
||||
label="值">
|
||||
</el-table-column>
|
||||
<el-table-column align="center"
|
||||
label="操作">
|
||||
<template slot-scope="scope">
|
||||
<div>
|
||||
<i class="el-icon-delete" @click="deleteGlobalEvent(scope.$index)"></i>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</el-collapse-item>
|
||||
</el-collapse>
|
||||
<GlobalEventListenerDialog @commitGlobalForm="commitGlobalForm"
|
||||
:dialogFormVisibleBool="showGlobalDialog"
|
||||
:formData="globalFormData" :element="element" :modeler="modeler" :globalFormTable="globalFormTable"></GlobalEventListenerDialog>
|
||||
<EventListenerDialog @commitEventForm="commitEventForm"
|
||||
:dialogFormVisibleBool="showEventDialog"
|
||||
:formData="eventFormData" :nodeElement="element" :modeler="modeler" :listenerTable="listenerTable"></EventListenerDialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import GlobalEventListenerDialog from "./dialog/GlobalEventListenerDialog"
|
||||
import EventListenerDialog from "./dialog/EventListenerDialog"
|
||||
export default {
|
||||
name: "ProcessProperty",
|
||||
data() {
|
||||
return {
|
||||
activeNames: ['1'],
|
||||
showGlobalDialog: false,
|
||||
showEventDialog: false,
|
||||
listenerTable: [
|
||||
|
||||
],
|
||||
globalFormTable: [
|
||||
|
||||
],
|
||||
globalFormData: {
|
||||
type:"start"
|
||||
},
|
||||
eventFormData: {
|
||||
event:"class",
|
||||
type:"start"
|
||||
},
|
||||
localProcessData:this.processData
|
||||
}
|
||||
},
|
||||
components: {
|
||||
GlobalEventListenerDialog,EventListenerDialog
|
||||
},
|
||||
props: {
|
||||
processData: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
modeler: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
element: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
var that = this
|
||||
if (this.element.businessObject
|
||||
&& this.element.businessObject.extensionElements
|
||||
&& this.element.businessObject.extensionElements.values) {
|
||||
that.globalFormTable = this.element.businessObject.extensionElements.values.filter(
|
||||
(item) => item.$type === 'activiti:EventListener'
|
||||
)
|
||||
that.listenerTable = this.element.businessObject.extensionElements.values.filter(
|
||||
(item) => {
|
||||
if (item.$type === 'activiti:ExecutionListener') {
|
||||
item.type = Object.keys(item)[1]
|
||||
item.class = item[Object.keys(item)[1]]
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
deleteGlobalEvent(index){
|
||||
const data = this.globalFormTable[index]
|
||||
if (this.element.businessObject
|
||||
&& this.element.businessObject.extensionElements
|
||||
&& this.element.businessObject.extensionElements.values) {
|
||||
// 排除全局监听类型 并且class为删除的class的数据。
|
||||
const filterArr = this.element.businessObject.extensionElements.values.filter(
|
||||
(item) => !(item.$type === 'activiti:EventListener' && item.class === data.class)
|
||||
)
|
||||
// 刷新数据
|
||||
let extensionElements = this.modeler.get("bpmnFactory").create("bpmn:ExtensionElements", {values: filterArr});
|
||||
this.modeler.get("modeling").updateProperties(this.element, {extensionElements});
|
||||
}
|
||||
this.globalFormTable.splice(index, 1);
|
||||
},
|
||||
deleteEvent(index){
|
||||
const data = this.listenerTable[index]
|
||||
if (this.element.businessObject
|
||||
&& this.element.businessObject.extensionElements
|
||||
&& this.element.businessObject.extensionElements.values) {
|
||||
// 排除全局监听类型 并且class为删除的class的数据。
|
||||
const filterArr = this.element.businessObject.extensionElements.values.filter(
|
||||
(item) => !(item.$type === 'activiti:ExecutionListener' && item.event === data.event && data.class === item[data.type])
|
||||
)
|
||||
// 刷新数据
|
||||
let extensionElements = this.modeler.get("bpmnFactory").create("bpmn:ExtensionElements", {values: filterArr});
|
||||
this.modeler.get("modeling").updateProperties(this.element, {extensionElements});
|
||||
}
|
||||
this.listenerTable.splice(index, 1);
|
||||
},
|
||||
showGlobalDialogMethod(){
|
||||
this.showGlobalDialog = true;
|
||||
this.globalFormData={
|
||||
type:"class"
|
||||
}
|
||||
},
|
||||
showEventDialogMethod(){
|
||||
this.showEventDialog = true;
|
||||
this.eventFormData= {
|
||||
event:"start",
|
||||
type:"class"
|
||||
}
|
||||
},
|
||||
updateId(name) {
|
||||
this.modeler.get("modeling").updateProperties(this.element, {id: name});
|
||||
},
|
||||
updateName(name) {
|
||||
this.modeler.get("modeling").updateProperties(this.element, {name: name});
|
||||
},
|
||||
updateDesc(name) {
|
||||
let doc = this.modeler.get("bpmnFactory").create("bpmn:Documentation", {text: name});
|
||||
this.modeler.get("modeling").updateProperties(this.element, {documentation: [doc]});
|
||||
console.log( this.modeler.get("modeling"))
|
||||
},
|
||||
commitEventForm(from){
|
||||
this.showEventDialog = false
|
||||
if (from != null) {
|
||||
this.listenerTable.push(from)
|
||||
}
|
||||
|
||||
},
|
||||
commitGlobalForm(from){
|
||||
this.showGlobalDialog = false
|
||||
if (from != null) {
|
||||
|
||||
this.globalFormTable.push(from)
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.title span{
|
||||
font-weight: bold;
|
||||
margin-left: 5px;
|
||||
}
|
||||
.el-tooltip__popper{
|
||||
font-size: 14px;
|
||||
max-width:50%;
|
||||
backgroud: #68859a !important; /*背景色 !important优先级*/
|
||||
}
|
||||
</style>
|
@ -0,0 +1,240 @@
|
||||
<template>
|
||||
<div>
|
||||
<!-- 开始节点 -->
|
||||
<el-collapse v-if="localFormData.type=='bpmn:StartEvent'" v-model="activeNames" accordion>
|
||||
<el-collapse-item name="1">
|
||||
<template slot="title">
|
||||
<div class="title">
|
||||
<i class="header-icon el-icon-setting"></i>
|
||||
<span>基本设置</span>
|
||||
</div>
|
||||
</template>
|
||||
<div>
|
||||
<el-form label-position="right" label-width="70px">
|
||||
<el-form-item label="节点类型">
|
||||
<el-input v-model="localFormData.type" disabled></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="ID">
|
||||
<el-input v-model="localFormData.id" @input="updateId"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="名称">
|
||||
<el-input v-model="localFormData.name " @input="updateName"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</el-collapse-item>
|
||||
<el-collapse-item name="2">
|
||||
<template slot="title">
|
||||
<div class="title">
|
||||
<i class="header-icon el-icon-setting"></i>
|
||||
<span>执行监听</span>
|
||||
</div>
|
||||
</template>
|
||||
<div>
|
||||
<div style="margin: 10px 3%;float: right">
|
||||
<el-button size="mini" plain @click="showEventDialogMethod">添加</el-button>
|
||||
</div>
|
||||
<el-table
|
||||
border :data="listenerTable"
|
||||
style="width: 93%;margin: 0 auto">
|
||||
<el-table-column align="center" prop="event"
|
||||
label="事件">
|
||||
</el-table-column>
|
||||
<el-table-column align="center" prop="type" :show-overflow-tooltip="true"
|
||||
label="类型">
|
||||
</el-table-column>
|
||||
<el-table-column align="center" prop="class" :show-overflow-tooltip="true"
|
||||
label="实现">
|
||||
</el-table-column>
|
||||
<el-table-column align="center"
|
||||
label="操作">
|
||||
<template slot-scope="scope">
|
||||
<div>
|
||||
<i class="el-icon-delete" @click="deleteEvent(scope.$index)"></i>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</el-collapse-item>
|
||||
|
||||
</el-collapse>
|
||||
<EventListenerDialog @commitEventForm="commitEventForm"
|
||||
:dialogFormVisibleBool="showEventDialog"
|
||||
:formData="eventFormData" :nodeElement="nodeElement" :modeler="modeler" :listenerTable="listenerTable"></EventListenerDialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import EventListenerDialog from "./dialog/EventListenerDialog"
|
||||
import GlobalEventListenerDialog from "./dialog/GlobalEventListenerDialog";
|
||||
export default {
|
||||
name: "NodePropertyPanel",
|
||||
data() {
|
||||
return {
|
||||
activeNames: ['1'],
|
||||
input3: 1,
|
||||
listenerTable: [],
|
||||
showEventDialog: false,
|
||||
eventFormData: {},
|
||||
bpmnData: {
|
||||
assignees: [{
|
||||
value: "${assignee}",
|
||||
label: "表达式"
|
||||
}, {
|
||||
value: "1001",
|
||||
label: "张三"
|
||||
}, {
|
||||
value: "1002",
|
||||
label: "李四"
|
||||
}, {
|
||||
value: "1003",
|
||||
label: "王五"
|
||||
}],
|
||||
candidateUsers:[{
|
||||
value: "1001",
|
||||
label: "张三"
|
||||
}, {
|
||||
value: "1002",
|
||||
label: "李四"
|
||||
}, {
|
||||
value: "1003",
|
||||
label: "王五"
|
||||
}],
|
||||
roles: [
|
||||
{
|
||||
value: "manager",
|
||||
label: "经理"
|
||||
},
|
||||
{
|
||||
value: "personnel",
|
||||
label: "人事"
|
||||
},
|
||||
{
|
||||
value: "charge",
|
||||
label: "主管"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
components: {
|
||||
EventListenerDialog
|
||||
},
|
||||
props: {
|
||||
modeler: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
nodeElement: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
formData:{
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
computed:{
|
||||
localFormData:{
|
||||
get(){
|
||||
return this.formData
|
||||
}
|
||||
}
|
||||
},
|
||||
watch:{
|
||||
nodeElement:{
|
||||
handler(){
|
||||
if(this.nodeElement.type==="bpmn:StartEvent"){
|
||||
this.updateName("开始");
|
||||
}
|
||||
if(this.nodeElement.type==="bpmn:EndEvent"){
|
||||
this.updateName("结束");
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
const that = this
|
||||
if (this.nodeElement.businessObject
|
||||
&& this.nodeElement.businessObject.extensionElements
|
||||
&& this.nodeElement.businessObject.extensionElements.values) {
|
||||
// 根据xml 组合当前节点的监听数据
|
||||
that.listenerTable = this.nodeElement.businessObject.extensionElements.values.filter(
|
||||
(item) => {
|
||||
if (item.$type === 'activiti:ExecutionListener') {
|
||||
item.type = Object.keys(item)[1]
|
||||
item.class = item[Object.keys(item)[1]]
|
||||
return true;
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
updateProperties(properties){
|
||||
console.log(this.nodeElement)
|
||||
console.log(properties)
|
||||
this.modeler.get("modeling").updateProperties(this.nodeElement, properties);
|
||||
},
|
||||
updateId(name) {
|
||||
this.updateProperties({id: name});
|
||||
},
|
||||
updateName(name) {
|
||||
this.updateProperties({name: name});
|
||||
},
|
||||
changeUserType() {
|
||||
},
|
||||
updateSequenceFlow(val){
|
||||
let newCondition = this.modeler.get("moddle").create('bpmn:FormalExpression', {
|
||||
body: val
|
||||
});
|
||||
this.updateProperties({conditionExpression:newCondition});
|
||||
},
|
||||
addUser(properties){
|
||||
this.updateProperties(properties);
|
||||
Object.assign(properties, {
|
||||
userType: Object.keys(properties)[0]
|
||||
});
|
||||
console.log(properties)
|
||||
this.$emit('modifyFormData',properties);
|
||||
},
|
||||
showEventDialogMethod(){
|
||||
this.showEventDialog = true;
|
||||
this.eventFormData= {
|
||||
event:"start",
|
||||
type:"class"
|
||||
}
|
||||
},
|
||||
deleteEvent(index){
|
||||
const data = this.listenerTable[index]
|
||||
if (this.nodeElement.businessObject
|
||||
&& this.nodeElement.businessObject.extensionElements
|
||||
&& this.nodeElement.businessObject.extensionElements.values) {
|
||||
// 排除全局监听类型 并且class为删除的class的数据。
|
||||
const filterArr = this.nodeElement.businessObject.extensionElements.values.filter(
|
||||
(item) => !(item.$type === 'activiti:ExecutionListener' && item.event === data.event && data.class === item[data.type])
|
||||
)
|
||||
// 刷新数据
|
||||
let extensionElements = this.modeler.get("bpmnFactory").create("bpmn:ExtensionElements", {values: filterArr});
|
||||
this.modeler.get("modeling").updateProperties(this.nodeElement, {extensionElements});
|
||||
}
|
||||
this.listenerTable.splice(index, 1);
|
||||
},
|
||||
commitEventForm(from){
|
||||
this.showEventDialog = false
|
||||
if (from != null) {
|
||||
this.listenerTable.push(from)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.title span{
|
||||
font-weight: bold;
|
||||
margin-left: 5px;
|
||||
}
|
||||
</style>
|
@ -0,0 +1,117 @@
|
||||
<template>
|
||||
<el-dialog title="自定义全局监听器" :visible.sync="dialogFormVisible" :before-close="close">
|
||||
<el-form :model="form">
|
||||
<el-form-item label="事件类型:" :label-width="formLabelWidth">
|
||||
<el-select v-model="form.type" placeholder="选择">
|
||||
<el-option label="类" value="class"></el-option>
|
||||
<el-option label="表达式" value="expression"></el-option>
|
||||
<el-option label="代理表达式" value="delegateExpression"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="事件类型:" :label-width="formLabelWidth">
|
||||
<el-select v-model="form.event" placeholder="选择">
|
||||
<el-option label="start" value="start"></el-option>
|
||||
<el-option label="take" value="take"></el-option>
|
||||
<el-option label="end" value="end"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="值:" :label-width="formLabelWidth">
|
||||
<el-input v-model="form.class" style="width: 50%"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button type="primary" @click="commitForm()">确 定</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "EventListenerDialog",
|
||||
data() {
|
||||
return {
|
||||
activeNames: ['1'],
|
||||
formLabelWidth: "200px",
|
||||
value: "类",
|
||||
options: [
|
||||
{
|
||||
value: "类",
|
||||
label: "类"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
props: {
|
||||
formData:{
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
dialogFormVisibleBool:{
|
||||
type: Boolean,
|
||||
required: false
|
||||
},
|
||||
modeler: {
|
||||
type: Object,
|
||||
required: false
|
||||
},
|
||||
nodeElement:{
|
||||
type: Object,
|
||||
required: false
|
||||
},
|
||||
listenerTable:{
|
||||
type: Array,
|
||||
required: false
|
||||
}
|
||||
},
|
||||
computed:{
|
||||
form:{
|
||||
get(){
|
||||
return this.formData;
|
||||
}
|
||||
},
|
||||
dialogFormVisible:{
|
||||
get(){
|
||||
return this.dialogFormVisibleBool
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
commitForm(){
|
||||
const from = this.form
|
||||
const filterArr = this.listenerTable.filter(
|
||||
(item) => (item.event === from.event && from.type === item.type && from.class === item.class)
|
||||
)
|
||||
if (filterArr.length !== 0) {
|
||||
this.$emit('commitEventForm', null);
|
||||
return
|
||||
}
|
||||
let data = {}
|
||||
data[from.type] = from.class
|
||||
data['event'] = from.event
|
||||
if (this.nodeElement.businessObject
|
||||
&& this.nodeElement.businessObject.extensionElements
|
||||
&& this.nodeElement.businessObject.extensionElements.values) {
|
||||
let eventListener = this.modeler.get("bpmnFactory").create("activiti:ExecutionListener", data);
|
||||
let extensionElements = this.modeler.get("bpmnFactory").create("bpmn:ExtensionElements",
|
||||
{values: this.nodeElement.businessObject.extensionElements.values.concat(eventListener),});
|
||||
this.modeler.get("modeling").updateProperties(this.nodeElement, {extensionElements});
|
||||
} else {
|
||||
|
||||
let eventListener = this.modeler.get("bpmnFactory").create("activiti:ExecutionListener", data);
|
||||
let extensionElements = this.modeler.get("bpmnFactory").create("bpmn:ExtensionElements", {values: [eventListener],});
|
||||
this.modeler.get("modeling").updateProperties(this.nodeElement, {extensionElements});
|
||||
}
|
||||
this.$emit('commitEventForm', this.form);
|
||||
},
|
||||
close(){
|
||||
this.$emit('commitEventForm', null);
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/deep/.el-dialog > .el-dialog__header{
|
||||
padding: 24px 20px
|
||||
}
|
||||
</style>
|
@ -0,0 +1,113 @@
|
||||
<template>
|
||||
<el-dialog title="自定义全局监听器" :visible.sync="dialogFormVisible" :before-close="close">
|
||||
<el-form :model="form">
|
||||
<el-form-item label="监听类型:" :label-width="formLabelWidth">
|
||||
<el-select v-model="form.type" placeholder="选择">
|
||||
<el-option label="类" value="class"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="值:" :label-width="formLabelWidth">
|
||||
<el-input v-model="form.class" style="width: 50%"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button type="primary" @click="commitForm()">确 定</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "GlobalEventListenerDialog",
|
||||
data() {
|
||||
return {
|
||||
activeNames: ['1'],
|
||||
listenerTable: [],
|
||||
formLabelWidth: "200px",
|
||||
value: "类",
|
||||
options: [
|
||||
{
|
||||
value: "类",
|
||||
label: "类"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
props: {
|
||||
formData:{
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
dialogFormVisibleBool:{
|
||||
type: Boolean,
|
||||
required: false
|
||||
},
|
||||
modeler: {
|
||||
type: Object,
|
||||
required: false
|
||||
},
|
||||
element:{
|
||||
type: Object,
|
||||
required: false
|
||||
},
|
||||
globalFormTable:{
|
||||
type: Array,
|
||||
required: false
|
||||
}
|
||||
},
|
||||
computed:{
|
||||
form:{
|
||||
get(){
|
||||
return this.formData;
|
||||
}
|
||||
},
|
||||
dialogFormVisible:{
|
||||
get(){
|
||||
return this.dialogFormVisibleBool
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
commitForm(){
|
||||
const from = this.formData;
|
||||
// 获取原数组中是否存在这个class了 如果存在就退出不操作
|
||||
const filterArr = this.globalFormTable.filter(
|
||||
(item) => item.class === from.class
|
||||
)
|
||||
if (filterArr.length !== 0) {
|
||||
this.$emit('commitGlobalForm', null);
|
||||
return
|
||||
}
|
||||
if (this.element.businessObject
|
||||
&& this.element.businessObject.extensionElements
|
||||
&& this.element.businessObject.extensionElements.values) {
|
||||
let eventListener = this.modeler.get("bpmnFactory").create("activiti:EventListener", from);
|
||||
let extensionElements = this.modeler.get("bpmnFactory").create("bpmn:ExtensionElements",
|
||||
{
|
||||
values: this.element.businessObject.extensionElements.values.concat(eventListener),
|
||||
}
|
||||
);
|
||||
this.modeler.get("modeling").updateProperties(this.element, {extensionElements});
|
||||
} else {
|
||||
let eventListener = this.modeler.get("bpmnFactory").create("activiti:EventListener", from);
|
||||
let extensionElements = this.modeler.get("bpmnFactory").create("bpmn:ExtensionElements",
|
||||
{
|
||||
values: [eventListener],
|
||||
}
|
||||
);
|
||||
this.modeler.get("modeling").updateProperties(this.element, {extensionElements});
|
||||
}
|
||||
this.$emit('commitGlobalForm', this.form);
|
||||
},
|
||||
close(){
|
||||
this.$emit('commitGlobalForm', null);
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/deep/.el-dialog > .el-dialog__header{
|
||||
padding: 24px 20px
|
||||
}
|
||||
</style>
|
@ -0,0 +1,173 @@
|
||||
<template>
|
||||
<el-dialog width="60%" title="用户选择" :visible.sync="dialogFormVisible" :before-close="close">
|
||||
<el-form>
|
||||
<el-row style="width: 93%;margin: 0 auto">
|
||||
<el-col :span="6">
|
||||
<el-form-item label="账户:" >
|
||||
<el-input v-model="searchData.account" style="width:80%" ></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-form-item label="昵称:">
|
||||
<el-input v-model="searchData.name" style="width:80%" ></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="5">
|
||||
<el-button type="primary">查询</el-button>
|
||||
<el-button >重置</el-button>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-form-item>
|
||||
<el-table v-show="type === 'assignee'"
|
||||
border :data="options"
|
||||
style="width: 93%;margin: 0 auto">
|
||||
<el-table-column align="center" prop="account"
|
||||
label="账户">
|
||||
</el-table-column>
|
||||
<el-table-column align="center" prop="name" :show-overflow-tooltip="true"
|
||||
label="昵称">
|
||||
</el-table-column>
|
||||
<el-table-column align="center"
|
||||
label="操作">
|
||||
<template slot-scope="scope">
|
||||
<div>
|
||||
<el-button type="primary" @click="commitForm(scope.$index)">选择</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-table v-show="type === 'candidateUsers'"
|
||||
border :data="options" @selection-change="handleSelectionChange"
|
||||
style="width: 93%;margin: 0 auto">
|
||||
<!--批量选择用户的时候需要复选框-->
|
||||
<el-table-column
|
||||
type="selection"
|
||||
width="55">
|
||||
</el-table-column>
|
||||
<el-table-column align="center" prop="account"
|
||||
label="账户">
|
||||
</el-table-column>
|
||||
<el-table-column align="center" prop="name" :show-overflow-tooltip="true"
|
||||
label="昵称">
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-pagination style="float: right;margin:20px 2.7% 0 0"
|
||||
background
|
||||
layout="prev, pager, next"
|
||||
:total="1000">
|
||||
</el-pagination>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<!--批量选择用户的时候需要确认按钮-->
|
||||
<div slot="footer" class="dialog-footer" v-if="type === 'candidateUsers'">
|
||||
<el-button type="primary" @click="commitForm()">确 定</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "UserSelectDialog",
|
||||
data() {
|
||||
return {
|
||||
activeNames: ['1'],
|
||||
formLabelWidth: "200px",
|
||||
value: "类",
|
||||
searchData: {},
|
||||
multipleSelection: [],
|
||||
options: [
|
||||
{
|
||||
name: "张三",
|
||||
account: "admin1"
|
||||
},
|
||||
{
|
||||
name: "李四",
|
||||
account: "admin2"
|
||||
},
|
||||
{
|
||||
name: "王五",
|
||||
account: "admin3"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
props: {
|
||||
formData:{
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
required: false
|
||||
},
|
||||
dialogFormVisibleBool:{
|
||||
type: Boolean,
|
||||
required: false
|
||||
},
|
||||
modeler: {
|
||||
type: Object,
|
||||
required: false
|
||||
},
|
||||
nodeElement:{
|
||||
type: Object,
|
||||
required: false
|
||||
}
|
||||
},
|
||||
computed:{
|
||||
form:{
|
||||
get(){
|
||||
return this.formData;
|
||||
}
|
||||
},
|
||||
dialogFormVisible:{
|
||||
get(){
|
||||
return this.dialogFormVisibleBool
|
||||
}
|
||||
}
|
||||
},
|
||||
watch:{
|
||||
type:{
|
||||
handler(){
|
||||
console.log(this.type)
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
},
|
||||
methods: {
|
||||
updateProperties(properties){
|
||||
this.modeler.get("modeling").updateProperties(this.nodeElement, properties);
|
||||
},
|
||||
commitForm(index){
|
||||
if (this.type === 'assignee') {
|
||||
this.modeler.get("modeling").updateProperties(this.nodeElement, {
|
||||
assignee: this.options[index].account
|
||||
});
|
||||
this.$emit('commitUserForm', this.options[index]);
|
||||
} else if(this.type === 'candidateUsers'){
|
||||
let updateStr = null
|
||||
let candidateUsersStr = this.multipleSelection.map(item => item.account);
|
||||
if (candidateUsersStr.length > 0) {
|
||||
updateStr = candidateUsersStr.join(",")
|
||||
}
|
||||
this.modeler.get("modeling").updateProperties(this.nodeElement, {
|
||||
candidateUsers: updateStr
|
||||
});
|
||||
this.$emit('commitUserForm', null);
|
||||
}
|
||||
},
|
||||
close(){
|
||||
this.$emit('commitUserForm', null);
|
||||
},
|
||||
handleSelectionChange(val) {
|
||||
this.multipleSelection = val;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/deep/.el-dialog > .el-dialog__header{
|
||||
padding: 24px 20px
|
||||
}
|
||||
</style>
|
220
yudao-admin-ui/src/components/bpmn/panel/index.vue
Normal file
220
yudao-admin-ui/src/components/bpmn/panel/index.vue
Normal file
@ -0,0 +1,220 @@
|
||||
<template>
|
||||
<div class="bpmn-panel">
|
||||
<el-container>
|
||||
<!-- <el-header height="45px">-->
|
||||
<!-- <div class="config-tab" :class="{active: configTab=='node'}" @click="handleConfigSelect('node')">节点属性</div>-->
|
||||
<!-- <div class="config-tab" :class="{active: configTab=='process'}" @click="handleConfigSelect('process')">流程属性</div>-->
|
||||
<!-- </el-header>-->
|
||||
<el-main>
|
||||
<!-- 节点的控制面板-->
|
||||
<node-property-panel v-if="configTab==='node'" :modeler="modeler" @modifyConfigTab="modifyConfigTab"
|
||||
:nodeElement="nodeElement" :formData="formData" @modifyFormData="modifyFormData"></node-property-panel>
|
||||
<start-event-node-property-panel v-if="configTab==='start-node'" :modeler="modeler" @modifyConfigTab="modifyConfigTab"
|
||||
:nodeElement="nodeElement" :formData="formData" @modifyFormData="modifyFormData"></start-event-node-property-panel>
|
||||
<!-- 流程的控制面板-->
|
||||
<process-property-panel v-if="configTab==='process'" :modeler="modeler" :process-data="process"
|
||||
:element="element"></process-property-panel>
|
||||
</el-main>
|
||||
</el-container>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import NodePropertyPanel from "./NodePropertyPanel";
|
||||
import ProcessPropertyPanel from "./ProcessPropertyPanel";
|
||||
import StartEventNodePropertyPanel from "./StartEventNodePropertyPanel";
|
||||
export default {
|
||||
name: "index",
|
||||
data() {
|
||||
return {
|
||||
configTab: 'process',
|
||||
panelIndex: 8,
|
||||
element: {},
|
||||
nodeElement: {},
|
||||
formData: {}
|
||||
}
|
||||
},
|
||||
props: {
|
||||
modeler: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
process: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.handleModeler();
|
||||
},
|
||||
methods: {
|
||||
handleConfigSelect(value) {
|
||||
this.configTab = value;
|
||||
},
|
||||
handleModeler() {
|
||||
const _this = this;
|
||||
this.modeler.on("root.added", e => {
|
||||
let element = e.element;
|
||||
if (this.isImplicitRoot(element)) {
|
||||
return;
|
||||
}
|
||||
this.element = element;
|
||||
});
|
||||
// 数据变化
|
||||
this.modeler.on("commandStack.changed", () => {
|
||||
_this.modeler.saveXML({format: true}, function (err, xml) {
|
||||
_this.$emit('updateXml', xml)
|
||||
});
|
||||
})
|
||||
//数据变化
|
||||
this.modeler.on("selection.changed", e => {
|
||||
const element = e.newSelection[0];
|
||||
if (!element) {
|
||||
return;
|
||||
}
|
||||
console.log("selection.changed: element", element)
|
||||
this.modifyConfigTab(element);
|
||||
this.handleFormData(element);
|
||||
this.changeFormData(element)
|
||||
})
|
||||
this.modeler.on("element.changed", e => {
|
||||
const {element} = e;
|
||||
if (!element) {
|
||||
return;
|
||||
}
|
||||
console.log("element.changed: element", element)
|
||||
this.handleFormData(element);
|
||||
this.changeFormData(element)
|
||||
});
|
||||
this.modeler.on("element.click", e => {
|
||||
const {element} = e;
|
||||
console.log("click: element", element)
|
||||
this.handleFormData(element)
|
||||
if (element.type == this.modeler._definitions.rootElements[0].$type) {
|
||||
this.modifyConfigTab(element)
|
||||
} else {
|
||||
this.modifyConfigTab(element)
|
||||
this.changeFormData(element)
|
||||
}
|
||||
})
|
||||
},
|
||||
changeFormData(element){
|
||||
const _this = this;
|
||||
if(element.type === "bpmn:UserTask"){
|
||||
let _businessObject = element.businessObject;
|
||||
if(_businessObject.assignee){
|
||||
_this.formData.userType = "assignee";
|
||||
_this.formData.assignee = _businessObject.assignee;
|
||||
}
|
||||
if (_this.formData.assignee) {
|
||||
_this.formData.userType = "assignee"
|
||||
}
|
||||
if (_this.formData.candidateGroups) {
|
||||
_this.formData.userType = "candidateGroups"
|
||||
}
|
||||
if (_this.formData.candidateUsers) {
|
||||
_this.formData.userType = "candidateUsers"
|
||||
}
|
||||
}
|
||||
},
|
||||
isImplicitRoot(element) {
|
||||
return element.id === '__implicitroot';
|
||||
},
|
||||
modifyConfigTab(element) {
|
||||
let configTab = 'node'
|
||||
if (element !== undefined
|
||||
&& element.type !== undefined
|
||||
&& element.type==="bpmn:Process") {
|
||||
configTab = 'process'
|
||||
}
|
||||
if (element !== undefined
|
||||
&& element.type !== undefined
|
||||
&& element.type==='bpmn:StartEvent') {
|
||||
configTab = 'start-node'
|
||||
}
|
||||
console.log("configTab:" + configTab)
|
||||
this.configTab = configTab
|
||||
},
|
||||
handleFormData(element) {
|
||||
if (!element.id) {
|
||||
return;
|
||||
}
|
||||
let businessObject = element.businessObject;
|
||||
this.formData = {
|
||||
type: element.type,
|
||||
id: businessObject.id,
|
||||
name: businessObject.name,
|
||||
userType: businessObject.$attrs.userType ? businessObject.$attrs.userType : businessObject.userType,
|
||||
assignee: businessObject.$attrs.assignee ? businessObject.$attrs.assignee : businessObject.assignee,
|
||||
candidateGroups: businessObject.$attrs.candidateGroups ? businessObject.$attrs.candidateGroups : businessObject.candidateGroups,
|
||||
candidateUsers: businessObject.$attrs.candidateUsers ? businessObject.$attrs.candidateUsers : businessObject.candidateUsers,
|
||||
sequenceFlow: businessObject.conditionExpression ? businessObject.conditionExpression.body : '',
|
||||
extensionElements: businessObject.extensionElements ? businessObject.extensionElements.values : null
|
||||
}
|
||||
console.log("formData",this.formData)
|
||||
this.nodeElement = element;
|
||||
},
|
||||
modifyFormData(data){
|
||||
this.formData.assignee = data.assignee;
|
||||
this.formData.userType = data.userType;
|
||||
}
|
||||
},
|
||||
components: {
|
||||
NodePropertyPanel, ProcessPropertyPanel, StartEventNodePropertyPanel
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.el-main{
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
/deep/.el-collapse .el-input__inner{
|
||||
height: 30px !important;
|
||||
line-height: 30px !important;
|
||||
}
|
||||
/deep/.el-collapse .el-form-item__content{
|
||||
height: 30px !important;
|
||||
line-height: 30px !important;
|
||||
}
|
||||
/deep/.el-collapse .el-form-item__label{
|
||||
height: 30px !important;
|
||||
line-height: 30px !important;
|
||||
}
|
||||
/deep/.el-collapse .el-form-item__label{
|
||||
font-size: 12px;
|
||||
}
|
||||
/deep/.el-collapse .el-form{
|
||||
margin-top: 10px;
|
||||
}
|
||||
/deep/.el-collapse .is-active{
|
||||
border-bottom: 1px solid #EBEEF5
|
||||
}
|
||||
.bpmn-panel {
|
||||
/*width: 350px;*/
|
||||
border: 1px solid #eeeeee;
|
||||
padding: 0 5px;
|
||||
}
|
||||
|
||||
.el-header {
|
||||
border-bottom: solid 2px #e4e7ed;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.config-tab {
|
||||
height: 43px;
|
||||
line-height: 43px;
|
||||
display: inline-block;
|
||||
width: 50%;
|
||||
text-align: center;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.config-tab.active {
|
||||
border-bottom: solid 2px #409EFF;
|
||||
}
|
||||
</style>
|
@ -98,6 +98,19 @@ export const constantRoutes = [
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '/bpmn',
|
||||
component: Layout,
|
||||
hidden: true,
|
||||
children: [
|
||||
{
|
||||
path: 'model',
|
||||
component: (resolve) => require(['@/views/bpm/model'], resolve),
|
||||
name: 'model',
|
||||
meta: { title: '工作流模型', icon: '' }
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '/job',
|
||||
component: Layout,
|
||||
|
138
yudao-admin-ui/src/views/bpm/model/index.vue
Normal file
138
yudao-admin-ui/src/views/bpm/model/index.vue
Normal file
@ -0,0 +1,138 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
|
||||
<el-form-item label="模型名字" prop="name">
|
||||
<el-input v-model="queryParams.name" placeholder="请输入模型名字" clearable style="width: 240px;" size="small"
|
||||
@keyup.enter.native="handleQuery"/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="cyan" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5">
|
||||
<el-button type="warning" icon="el-icon-download" size="mini" @click="handleExport"
|
||||
v-hasPermi="['system:login-log:export']">导出</el-button>
|
||||
<el-button type="warning" icon="el-icon-download" size="mini" @click="openBpmn"
|
||||
v-hasPermi="['system:login-log:export']">新建</el-button>
|
||||
</el-col>
|
||||
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
|
||||
</el-row>
|
||||
|
||||
<el-table v-loading="loading" :data="list">
|
||||
<el-table-column label="ID" align="center" prop="id" />
|
||||
<el-table-column label="name" align="center" prop="metaInfo" >
|
||||
<template slot-scope="scope">
|
||||
<span>{{ scope.row.metaInfo ? JSON.parse(scope.row.metaInfo).name : "" }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="description" align="center" prop="metaInfo" >
|
||||
<template slot-scope="scope">
|
||||
<span>{{ JSON.parse(scope.row.metaInfo).description }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<pagination v-show="total>0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
|
||||
@pagination="getList"/>
|
||||
<el-dialog title="新建流程" :visible.sync="showBpmnBool" :before-close="close" :fullscreen="true">
|
||||
<vue-bpmn product="activiti" @processSave="processSave"></vue-bpmn>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { page } from "@/api/bpm/model";
|
||||
import VueBpmn from "@/components/bpmn/VueBpmn";
|
||||
|
||||
export default {
|
||||
name: "model",
|
||||
data() {
|
||||
return {
|
||||
// 遮罩层
|
||||
loading: true,
|
||||
// 显示搜索条件
|
||||
showSearch: true,
|
||||
showBpmnBool: false,
|
||||
// 总条数
|
||||
total: 0,
|
||||
// 表格数据
|
||||
list: [],
|
||||
bpmnXML: null,
|
||||
// 查询参数
|
||||
queryParams: {
|
||||
pageNo: 1,
|
||||
pageSize: 10
|
||||
}
|
||||
};
|
||||
},
|
||||
components: {VueBpmn},
|
||||
created() {
|
||||
this.getList();
|
||||
},
|
||||
methods: {
|
||||
/** 查询登录日志列表 */
|
||||
getList() {
|
||||
this.loading = true;
|
||||
page(this.queryParams).then(response => {
|
||||
this.list = response.data.list;
|
||||
this.total = response.data.total;
|
||||
this.loading = false;
|
||||
}
|
||||
);
|
||||
},
|
||||
// 登录状态字典翻译
|
||||
statusFormat(row, column) {
|
||||
return this.selectDictLabel(this.statusOptions, row.status);
|
||||
},
|
||||
/** 搜索按钮操作 */
|
||||
handleQuery() {
|
||||
this.queryParams.pageNo = 1;
|
||||
this.getList();
|
||||
},
|
||||
/** 重置按钮操作 */
|
||||
resetQuery() {
|
||||
this.dateRange = [];
|
||||
this.resetForm("queryForm");
|
||||
this.handleQuery();
|
||||
},
|
||||
/** 导出按钮操作 */
|
||||
handleExport() {
|
||||
const queryParams = this.queryParams;
|
||||
this.$confirm('是否确认导出所有操作日志数据项?', "警告", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning"
|
||||
}).then(function() {
|
||||
return exportLoginLog(queryParams);
|
||||
}).then(response => {
|
||||
this.downloadExcel(response, '登录日志.xls');
|
||||
})
|
||||
},
|
||||
processSave() {
|
||||
console.log("processSave")
|
||||
},
|
||||
openBpmn() {
|
||||
this.showBpmnBool = true
|
||||
},
|
||||
close() {
|
||||
this.showBpmnBool = false
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style>
|
||||
.el-dialog > .el-dialog__body{
|
||||
margin: 0;
|
||||
border: 0;
|
||||
}
|
||||
.bpmn-viewer-header{
|
||||
background: white;
|
||||
}
|
||||
.v-modal{
|
||||
z-index: 2000!important;
|
||||
}
|
||||
</style>
|
||||
|
Loading…
Reference in New Issue
Block a user