正所谓百家争鸣、见仁见智、众说纷纭、各有千秋!在工作流bpmn2.0可视化建模工具实现的细分领域,网上扑面而来的是 bpmn.js 这个渲染工具包和web建模器,而笔者却认为使用flowable官方开源 editor-app 才是王道。
Flowable 开源版本中的 web 版流程设计器editor-app,展示风格和功能基本跟 activiti-modeler 一样,集成简单,开发工作量小,界面美观大方,功能强大,用户体验友好。
通过以下两张Gif动图来个PK,您的直观感受如何呢?
bpmn.js运行效果图(gif动图取自互联网)
Flowable editor-app运行效果:
boot-admin 是一款采用前后端分离模式、基于SpringCloud微服务架构的SaaS后台管理框架。系统内置基础管理、权限管理、运行管理、定义管理、代码生成器和办公管理6个功能模块,集成分布式事务Seata、工作流引擎Flowable、业务规则引擎Drools、后台作业调度框架Quartz等,技术栈包括Mybatis-plus、Redis、Nacos、Seata、Flowable、Drools、Quartz、SpringCloud、Springboot Admin Gateway、Liquibase、jwt、Openfeign、I18n等。
gitee源码地址
github源码地址
下面介绍 boot-admin 对flowable官方bpmn2.0可视化建模工具 editor-app 的集成改造步骤:
modeler.html内容:
Activiti Editor
{{alerts.current.message}}
{{alerts.queue.length + 1}}
var ACTIVITI = ACTIVITI || {};
ACTIVITI.CONFIG = {
'contextRoot' : 'http://网关IP:网关端口号/api/workflow/auth/activiti',
};
var KISBPM = KISBPM || {};
KISBPM.URL = {
//通过modelId,获取已保存模型的json数据
getModel: function(modelId) {
return ACTIVITI.CONFIG.contextRoot + '/model/json?modelId=' + modelId;
},
//获取汉化资源json数据
getStencilSet: function() {
return ACTIVITI.CONFIG.contextRoot + '/editor/stencilset?version=' + Date.now();
},
//保存模型数据
putModel: function(modelId) {
return ACTIVITI.CONFIG.contextRoot + '/model/save?modelId=' + modelId;
},
//从cookie中读取令牌
getToken: function() {
var cookies = document.cookie;
var list = cookies.split("; "); // 解析出名/值对列表
for (var i = 0; i
$http({method: 'GET',
headers: {
'X-Token': KISBPM.URL.getToken()
},
url: KISBPM.URL.getStencilSet()})
.success(function (data, status, headers, config) {
var quickMenuDefinition = ['UserTask', 'EndNoneEvent', 'ExclusiveGateway',
'CatchTimerEvent', 'ThrowNoneEvent', 'TextAnnotation',
'SequenceFlow', 'Association'];
var ignoreForPaletteDefinition = ['SequenceFlow', 'MessageFlow', 'Association', 'DataAssociation', 'DataStore', 'SendTask'];
var quickMenuItems = [];
var morphRoles = [];
for (var i = 0; i 0) {
currentGroup = findGroup(currentGroupName, stencilItemGroups); // Find group in root groups array
if (currentGroup === null) {
currentGroup = addGroup(currentGroupName, stencilItemGroups);
}
// Add all child groups (if any)
for (var groupIndex = 1; groupIndex 0) {
stencilItem.customIcon = true;
stencilItem.icon = data.stencils[stencilIndex].customIconId;
}
if (!removed) {
if (quickMenuDefinition.indexOf(stencilItem.id) >= 0) {
quickMenuItems[quickMenuDefinition.indexOf(stencilItem.id)] = stencilItem;
}
}
if (stencilItem.id === 'TextAnnotation' || stencilItem.id === 'BoundaryCompensationEvent') {
stencilItem.canConnectAssociation = true;
}
for (var i = 0; i
function fetchModel(modelId) {
var modelUrl = KISBPM.URL.getModel(modelId);
$http({method: 'GET',
headers: {'X-Token': KISBPM.URL.getToken()},
url: modelUrl}).
success(function (data, status, headers, config) {
$rootScope.editor = new ORYX.Editor(data);
$rootScope.modelData = angular.fromJson(data);
$rootScope.editorFactory.resolve();
}).
error(function (data, status, headers, config) {
console.log('Error loading model with id ' + modelId + ' ' + data);
});
}
$http({ method: 'PUT',
data: params,
ignoreErrors: true,
headers: {'Accept': 'application/json',
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
'X-Token': KISBPM.URL.getToken()},
transformRequest: function (obj) {
var str = [];
for (var p in obj) {
str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
}
return str.join("&");
},
url: KISBPM.URL.putModel(modelMetaData.modelId)})
.success(function (data, status, headers, config) {
$scope.editor.handleEvents({
type: ORYX.CONFIG.EVENT_SAVED
});
$scope.modelData.name = $scope.saveDialog.name;
$scope.modelData.lastUpdated = data.lastUpdated;
$scope.status.loading = false;
$scope.$hide();
// Fire event to all who is listening
var saveEvent = {
type: KISBPM.eventBus.EVENT_TYPE_MODEL_SAVED,
model: params,
modelId: modelMetaData.modelId,
eventType: 'update-model'
};
KISBPM.eventBus.dispatch(KISBPM.eventBus.EVENT_TYPE_MODEL_SAVED, saveEvent);
// Reset state
$scope.error = undefined;
$scope.status.loading = false;
// Execute any callback
if (successCallback) {
successCallback();
}
})
.error(function (data, status, headers, config) {
$scope.error = {};
console.log('Something went wrong when updating the process model:' + JSON.stringify(data));
$scope.status.loading = false;
});
查询
重置
关闭
刷新
新建
查询
{{ props.row.id }}
{{ props.row.key }}
{{ props.row.name }}
{{ props.row.version }}
{{ $commonUtils.dateTimeFormat(props.row.createTime) }}
{{ $commonUtils.dateTimeFormat(props.row.lastUpdateTime) }}
修改
删除
部署
XML
workflow-model.js
import request from '@/utils/request'
//分页获取模型数据
export function fetchModelPage(data) {
return request({
url: '/api/workflow/auth/activiti/model/page',
method: 'post',
data
})
}
//保存模型
export function saveNewModel(data) {
return request({
url: '/api/workflow/auth/activiti/model/add',
method: 'post',
data
})
}
//删除模型数据
export function delModel(data) {
return request({
url: '/api/workflow/auth/activiti/model/del',
method: 'post',
data
})
}
//部署模型
export function deployModel(data) {
return request({
url: '/api/workflow/auth/activiti/model/deploy',
method: 'post',
data
})
}
//获取模型XML
export function fetchXml(data) {
return request({
url: '/api/workflow/auth/activiti/model/xml',
method: 'post',
data
})
}
对应前端需求,后端主要实现使用flowable引擎,获取汉化资源、读取模型数据、保存模型数据三个功能。
具体内容参见下一篇博文
本文来自博客园,作者:超然楼,转载请注明原文链接:https://www.cnblogs.com/soft1314/p/17338370.html
参与评论
手机查看
返回顶部