最近一直在做工作流的相关开发工作,自己也搭建了一个工作流的管理平台来方便开发调试。这里记录一下相关的工作。

工作流的引擎我采用的是业界流行的Camunda,这个引擎基于BPMN/DMN的标准来实现工作流,可以很方便的进行工作流的编排,实现低代码运行,以及业务逻辑编排等功能。

具体如何运行Camunda引擎在我之前的博客有介绍,这里不再重复,只描述一下如何搭建一个网站来实现工作流的管理。其实Camunda也提供了WEB的应用来管理工作流,但是如果自己有一些额外的需求,要进行一些自定义的功能,那么最好是自己开发一个WEB应用,通过调用Camunda引擎提供的API接口来实现对工作流的管理。

我选择用webpack+bootstrap的框架来快速搭建一个简单漂亮的Web应用。首先是用webpack来进行初始化的工作,新建一个名为workflow-manager的文件夹,在里面运行以下命令:

npm init -y
npm install webpack webpack-cli --save-dev
npm install copy-webpack-plugin --save-dev
npm install jquery bootstrap@4.6.2 feather-icons --save
npm install style-loader css-loader less-loader raw-loader --save-dev

在这个文件夹里面新建一个src目录,我们的html, js等文件都将放置在这个目录下.

在src目录里面我们新建一个workflow.html文件,内容如下:

<!doctype html>
<html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"><meta name="description" content=""><meta name="author" content="Mark Otto, Jacob Thornton, and Bootstrap contributors"><meta name="generator" content="Hugo 0.101.0"><title>Workflow Management</title><link rel="canonical" href="https://getbootstrap.com/docs/4.6/examples/dashboard/"><!-- Bootstrap core CSS --><link href="assets/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet"><style>.bd-placeholder-img {font-size: 1.125rem;text-anchor: middle;-webkit-user-select: none;-moz-user-select: none;-ms-user-select: none;user-select: none;}@media (min-width: 768px) {.bd-placeholder-img-lg {font-size: 3.5rem;}}</style><!-- Custom styles for this template --><link href="assets/workflow.css" rel="stylesheet"></head><body><nav class="navbar navbar-dark sticky-top bg-dark flex-md-nowrap p-0 shadow"><a class="navbar-brand col-md-3 col-lg-2 mr-0 px-3" href="#">Company name</a><button class="navbar-toggler position-absolute d-md-none collapsed" type="button" data-toggle="collapse" data-target="#sidebarMenu" aria-controls="sidebarMenu" aria-expanded="false" aria-label="Toggle navigation"><span class="navbar-toggler-icon"></span></button><ul class="navbar-nav px-3"><li class="nav-item text-nowrap"><a class="nav-link" href="#">Sign out</a></li></ul></nav><div class="container-fluid"><div class="row"><nav id="sidebarMenu" class="col-md-3 col-lg-2 d-md-block bg-light sidebar collapse"><div class="sidebar-sticky pt-3"><ul class="nav flex-column"><li class="nav-item"><a class="nav-link active" href="#"><span data-feather="home"></span>Edit Workflow <span class="sr-only">(current)</span></a></li><li class="nav-item"><a class="nav-link" href="#"><span data-feather="file"></span>View Workflow</a></li><li class="nav-item"><a class="nav-link" href="#"><span data-feather="shopping-cart"></span>Edit Rule</a></li><li class="nav-item"><a class="nav-link" href="#"><span data-feather="users"></span>View Rule</a></li><li class="nav-item"><a class="nav-link" href="#"><span data-feather="bar-chart-2"></span>Reports</a></li><li class="nav-item"><a class="nav-link" href="#"><span data-feather="layers"></span>Integrations</a></li></ul></div></nav><main role="main" class="col-md-9 ml-sm-auto col-lg-10 px-md-4"><div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom"><h1 class="h2">New/Edit Workflow</h1><div class="btn-toolbar mb-2 mb-md-0"><div class="btn-group mr-2"><button type="button" class="btn btn-sm btn-outline-secondary">Download</button><button type="button" class="btn btn-sm btn-outline-secondary">Deploy</button></div></div></div></main></div></div><script src="assets/jquery/dist/jquery.slim.min.js"></script><script src="assets/bootstrap/dist/bootstrap.bundle.min.js"></script><script src="assets/feather-icons/dist/feather.min.js"></script><script src="workflow.bundle.js"></script></body>
</html>

在这个html里面,可以看到引用了放置在本地的bootstrap的js, CSS,以及jquery,feather库的js文件。我们需要修改一下webpack.config.js文件,把node_modules里面安装的对应文件拷贝出来。这里需要用到前面安装的copy-webpack-plugin来进行拷贝。在文件夹的根目录新建一个webpack.config.js文件,内容如下:

var CopyPlugin = require('copy-webpack-plugin');const path = require('path');module.exports = {entry: {workflow: './src/workflow.js',},output: {filename: '[name].bundle.js',path: path.resolve(__dirname, 'dist'),clean: true,},module: {rules: [{test: /\.css$/i,use: ['style-loader', 'css-loader'],},{test: /\.less$/i,use: ['style-loader', 'css-loader', 'less-loader'],},{test: /\.(png|svg|jpg|jpeg|gif)$/i,type: 'asset/resource',}],},plugins: [new CopyPlugin({patterns: [{ from: 'node_modules/jquery/dist/jquery.slim.min.js', to: 'assets/jquery/dist' },{ from: 'node_modules/bootstrap/dist/css/bootstrap.min.css', to: 'assets/bootstrap/dist/css' },{ from: 'node_modules/bootstrap/dist/js/bootstrap.bundle.min.js', to: 'assets/bootstrap/dist' },{ from: 'node_modules/feather-icons/dist/feather.min.js', to: 'assets/feather-icons/dist' },{ from: 'src/workflow.html', to: 'workflow.html' },{ from: 'src/workflow.css', to: 'assets/' },]}),]
};

简要介绍一下,这里面的内容的entry, output部分描述了把src目录下的js文件编译为dist目录下的对应js文件(文件名增加了.bundle的字符)。module里面定义了解析不同后缀的文件所需要加载的loader。plugin里面定义了用copy-webpack-plugin来把文件拷贝到dist目录下。

最后我们修改一下package.json文件,增加命令来进行npm run build,编译拷贝文件到dist目录,内容如下:

{"name": "dashboard","version": "1.0.0","description": "","private": true,"scripts": {"test": "echo \"Error: no test specified\" && exit 1","build": "webpack"},"keywords": [],"author": "","license": "ISC","devDependencies": {"copy-webpack-plugin": "^11.0.0","webpack": "^5.74.0","webpack-cli": "^4.10.0"},"dependencies": {"bootstrap": "^4.6.2","feather-icons": "^4.29.0","jquery": "^3.6.1"}
}

在根目录下运行npm run build命令,等待执行完成后,在dist目录我们就可以找到编译后的内容了。在web服务器中访问dist目录的workflow.html文件,即可成功显示页面。

下一步我们需要修改这个workflow.html,使得可以进行Camunda workflow的编辑和部署。首先需要用npm安装相关的包:

npm install --save bpmn-js
npm install --save bpmn-js-properties-panel @bpmn-io/properties-panel
npm install --save camunda-bpmn-moddle
npm install --save axios
npm install --save keycloak-js

修改webpack.config.js文件,在module->rules里面增加一条规则,处理bpmn文件的加载。在copyplugin里面增加两行语句,把bpmn-js库里面的样式拷贝到本地。修改后的文件内容如下:

var CopyPlugin = require('copy-webpack-plugin');const path = require('path');module.exports = {entry: {workflow: './src/workflow.js',},output: {filename: '[name].bundle.js',path: path.resolve(__dirname, 'dist'),clean: true,},module: {rules: [{test: /\.css$/i,use: ['style-loader', 'css-loader'],},{test: /\.less$/i,use: ['style-loader', 'css-loader', 'less-loader'],},{test: /\.(png|svg|jpg|jpeg|gif)$/i,type: 'asset/resource',},{test: /\.bpmn$/i,use: ['raw-loader'],},],},plugins: [new CopyPlugin({patterns: [{ from: 'node_modules/jquery/dist/jquery.slim.min.js', to: 'assets/jquery/dist' },{ from: 'node_modules/bootstrap/dist/css/bootstrap.min.css', to: 'assets/bootstrap/dist/css' },{ from: 'node_modules/bootstrap/dist/js/bootstrap.bundle.min.js', to: 'assets/bootstrap/dist' },{ from: 'node_modules/feather-icons/dist/feather.min.js', to: 'assets/feather-icons/dist' },{ from: 'src/workflow.html', to: 'workflow.html' },{ from: 'src/workflow.css', to: 'assets/' },{ from: 'node_modules/bpmn-js/dist/assets', to: 'vendor/bpmn-js/dist/assets' },{ from: 'node_modules/bpmn-js-properties-panel/dist/assets', to: 'vendor/bpmn-js-properties-panel/dist/assets' },]}),]
};

修改workflow.html文件,在<head>里面引入四个style文件

<link rel="stylesheet" href="vendor/bpmn-js/dist/assets/diagram-js.css">
<link rel="stylesheet" href="vendor/bpmn-js/dist/assets/bpmn-js.css">
<link rel="stylesheet" href="vendor/bpmn-js/dist/assets/bpmn-font/css/bpmn-embedded.css">
<link rel="stylesheet" href="vendor/bpmn-js-properties-panel/assets/properties-panel.css" />

在<body>的<main>里面增加以下容器,用于放置bpmn编辑器:

          <div class="content" id="js-drop-zone"><div class="message intro"><div class="note">把本地的BPMN文件拖到浏览器或者 <a id="js-create-diagram" href>新建一个新的工作流</a></div></div><div class="message error"><div class="note"><p>出问题了,无法展示BPMN 2.0图表</p><div class="details"><span>问题原因</span><pre></pre></div></div></div><div class="canvas" id="js-canvas"></div><div class="properties-panel-parent" id="js-properties-panel"></div></div>

这里面引入了一些新的样式定义,我们可以新建一个workflow.less文件,把这些样式定义在这个文件里面:

* {box-sizing: border-box;
}body,
html {height: 100%;max-height: 100%;padding: 0;margin: 0;
}#js-properties-panel {width: 400px;
}a:link {text-decoration: none;
}.content {position: relative;width: 100%;height: 100%;display: flex;> .message {width: 100%;height: 100%;text-align: center;display: table;font-size: 16px;color: #111;.note {vertical-align: middle;text-align: center;display: table-cell;}&.error {.details {max-width: 500px;font-size: 12px;margin: 20px auto;text-align: left;color: #BD2828;}pre {border: solid 1px #BD2828;background: #fefafa;padding: 10px;color: #BD2828;}}}&:not(.with-error) .error,&.with-error .intro,&.with-diagram .intro {display: none;}.canvas {width: 100%;height: 100%;}.canvas,.properties-panel-parent {display: none;}&.with-diagram {.canvas,.properties-panel-parent  {display: block;}}
}.buttons {position: fixed;bottom: 20px;left: 20px;padding: 0;margin: 0;list-style: none;> li {display: inline-block;margin-right: 10px;> a {background: #DDD;border: solid 1px #666;display: inline-block;padding: 5px;}}a {opacity: 0.3;}a.active {opacity: 1.0;}
}.properties-panel-parent {border-left: 1px solid #ccc;overflow: auto;&:empty {display: none;}> .djs-properties-panel {padding-bottom: 70px;min-height:100%;}
}

新建workflow.js文件,如以下内容,这里要注意的是我引入了keycloak,因此会要求用户进行认证。具体如何配置camunda与keycloak集成,可以参考我之前的文章:Camunda工作流平台与Keycloak的集成_gzroy的博客-CSDN博客

import $ from 'jquery';
import './workflow.less';
import BpmnModeler from 'bpmn-js/lib/Modeler';
import diagramXML from './diagram.bpmn';
import Keycloak from 'keycloak-js';
import axios from 'axios';
import config from './config.json';import {BpmnPropertiesPanelModule,BpmnPropertiesProviderModule,CamundaPlatformPropertiesProviderModule
} from 'bpmn-js-properties-panel';import CamundaBpmnModdle from 'camunda-bpmn-moddle/resources/camunda.json';
import customTranslate from './customTranslate/customTranslate';var customTranslateModule = {translate: [ 'value', customTranslate ]};var modeler = new BpmnModeler({container: '#js-canvas',propertiesPanel: {parent: '#js-properties-panel'},additionalModules: [BpmnPropertiesPanelModule,BpmnPropertiesProviderModule,CamundaPlatformPropertiesProviderModule,customTranslateModule],moddleExtensions: {camunda: CamundaBpmnModdle}
});var container = $('#js-drop-zone');
var token;function initKeycloak() {const keycloak = new Keycloak();keycloak.init({onLoad: 'login-required'}).then(function(authenticated) {if (authenticated) {console.log(keycloak.token);token = keycloak.token;}}).catch(function() {alert('登录失败');});
}$('body').on('load', initKeycloak());// Deployment button
$('#js-deployment').on("click", async function(event){const { xml } = await modeler.saveXML({ format: true });const parser = new DOMParser();const xmldoc = parser.parseFromString(xml, "application/xml");const processes = xmldoc.getElementsByTagName('bpmn2:process');const process_name = processes[0].getAttribute('name');const file = new File([xml], "diagram.bpmn", {type: "text/plain"});const { svg } = await modeler.saveSVG();const img_file = new File([svg], "diagram.svg", {type: "image/svg+xml"});const data = new FormData();data.append("deployment-name", process_name);data.append("deployment-source", "process application");data.append("data", file);data.append("diagram", img_file);axios.create({withCredentials: true}).post(config.baseurl+'/engine-rest/deployment/create', data, {headers: {'Content-Type':'multipart/form-data', 'Authorization': 'Bearer '+token}}).then(res=>{if (res.status==200) {alert("部署成功,点击链接查看:"+res.data.links[0].href);}});
});function createNewDiagram() {openDiagram(diagramXML);
}async function openDiagram(xml) {try {await modeler.importXML(xml);container.removeClass('with-error').addClass('with-diagram');} catch (err) {container.removeClass('with-diagram').addClass('with-error');container.find('.error pre').text(err.message);console.error(err);}
}function registerFileDrop(container, callback) {function handleFileSelect(e) {e.stopPropagation();e.preventDefault();var files = e.dataTransfer.files;var file = files[0];var reader = new FileReader();reader.onload = function(e) {var xml = e.target.result;callback(xml);};reader.readAsText(file);}function handleDragOver(e) {e.stopPropagation();e.preventDefault();e.dataTransfer.dropEffect = 'copy'; // Explicitly show this is a copy.}container.get(0).addEventListener('dragover', handleDragOver, false);container.get(0).addEventListener('drop', handleFileSelect, false);
}// file drag / drop ///
// check file api availability
if (!window.FileList || !window.FileReader) {window.alert('Looks like you use an older browser that does not support drag and drop. ' +'Try using Chrome, Firefox or the Internet Explorer > 10.');} else {registerFileDrop(container, openDiagram);console.log("registered");
}// bootstrap diagram functions
$(function() {$('#js-create-diagram').on('click', function(e) {e.stopPropagation();e.preventDefault();createNewDiagram();});var downloadLink = $('#js-download-diagram');var downloadSvgLink = $('#js-download-svg');$('.buttons a').on('click', function(e) {if (!$(this).is('.active')) {e.preventDefault();e.stopPropagation();}});function setEncoded(link, name, data) {var encodedData = encodeURIComponent(data);if (data) {link.addClass('active').attr({'href': 'data:application/bpmn20-xml;charset=UTF-8,' + encodedData,'download': name});} else {link.removeClass('active');}}var exportArtifacts = debounce(async function() {try {const { svg } = await modeler.saveSVG();setEncoded(downloadSvgLink, 'diagram.svg', svg);} catch (err) {console.error('Error happened saving svg: ', err);setEncoded(downloadSvgLink, 'diagram.svg', null);}try {const { xml } = await modeler.saveXML({ format: true });setEncoded(downloadLink, 'diagram.bpmn', xml);} catch (err) {console.error('Error happened saving XML: ', err);setEncoded(downloadLink, 'diagram.bpmn', null);}}, 500);modeler.on('commandStack.changed', exportArtifacts);
});// helpers //
function debounce(fn, timeout) {var timer;return function() {if (timer) {clearTimeout(timer);}timer = setTimeout(fn, timeout);};
}

最后运行npm run build编译之后,在Web服务器运行workflow.html,效果如下:

workflow_demo

搭建一个自定义的工作流管理平台(一)相关推荐

  1. 搭建一个自定义的工作流管理平台(二)

    在上一篇里面我搭建了一个Web的工作流管理平台,实现了对工作流的编辑和部署.现在我们继续完善这个工作流平台的功能,增加查看已部署的工作流,对工作流进行启动,查看执行结果等功能. 要查看已部署的工作流的 ...

  2. 如何搭建一个内部组件共享平台

    如今前端越来越趋于组件化的开发方式,最大的益处就是UI页面和逻辑的共用. 在开发者的眼里,如果你打开一个网站,组件化的开发方式会让你看起来像这个样子: 逻辑功能上我们会封装成一个库,然后NPM发布到公 ...

  3. 从零开始搭建一个测试技术练习平台

    工作中,要不断学习,为了快速上手,我打算写一个有增删改查功能的Javaweb项目,方便以后练习各种测试技术. 环境准备 1.准备一台电脑 2.官网下载最新版Intellij IDEA,破解步骤找&qu ...

  4. FPGA的设计艺术(17)如何搭建一个简易的逻辑测试平台?

    前言 提到FPGA逻辑的仿真,一般指的是行为仿真或者功能仿真,还有人会称为前仿,不包含时间延迟信息,只验证逻辑功能.对于小模块的仿真,需要写一个测试文件,英文是testbench,即测试平台.在tes ...

  5. 搭建一个大数据分析处理平台,主要划分为哪几步?

    (1)操作系统的选择操作系统一般使用开源版的RedHat.Centos或者Debian作为底层的构建平台,要根据大数据平台所要搭建的数据分析工具可以支持的系统,正确的选择操作系统的版本. (2)搭建H ...

  6. 搭建一个在线教育直播平台

    搭建一个在线直播系统需要满足的基本功能 流畅稳定的直播系统,满足师生音视频互动 对直播课程进行录制,方便学生复习老师可以 分享PPT.视频.图片等,便于教学 有丰富的互动功能,比如抢题答题等 能够供老 ...

  7. ELK快速搭建一个集中化日志平台

    在项目初期的时候,大家都是赶着上线,一般来说对日志没有过多的考虑,当然日志量也不大,所以用log4net就够了,随着应用的越来越多,日志散 落在各个服务器的logs文件夹下,确实有点不大方便,这个时候 ...

  8. 从零搭建一个机器人仿真的平台

    搭建ROS(机器人操作系统)和ROS2 ROS2可以在macOS.Windows.Linux.Debian和Ubuntu上安装,参考教程:ROS2的安装 ROS只可以安装在Ubuntu系统之上,从零开 ...

  9. 我不是网管 - 10分钟搭建一个校园课程直播平台

    系统概要 酷瓜云课堂局域网版,满足校园课程直播需求,提供包括音视频存储管理.音视频转码处理.音视频加密处理.在线直播和录播的一站式解决方案.所有服务都本地部署,没有外部依赖,文件和数据库都在本地,安全 ...

最新文章

  1. 设计模式 — 行为型模式 — 迭代器模式
  2. HTMLCSS学习笔记(四)----浮动原理及清浮动
  3. linux关机_Linux系统管理:开机启动流程(一)
  4. Uboot启动过程详解
  5. Java基本语法(15)--while循环结构do-while循环结构
  6. 天价部队到老家赶来java作文_天价与廉价作文800字
  7. 性能测试--jmeter如何发送get请求【3】
  8. WPF DataGrid 获取当前行某列值
  9. 个人收藏的移动端网页布局rem解决方案
  10. FZU 1502 Letter Deletion
  11. 代理ip网速慢的原因
  12. redis.exceptions.ResponseError: Command # 2 (HDEL select_6 1) of pipeline caused error: WRONGTYPE Op
  13. R语言入门——一文讲明白attach与detach
  14. 金三银四,我为面试所准备的面试题,不看要遭老罪喽
  15. 鹏业安装算量软件V8.0.0 Build 60(及58)升级内容
  16. 【深度学习】ICPR 2022|3DUNet:卷积+胶囊强强联手,医学图像分割的新良方
  17. [机缘参悟-82]:企业、HR、管理者激励员工的本质
  18. 最大化参数 火车头_火车头采集:网址参数设置教程[参数N]
  19. Service id not legal hostname (service_cmn)
  20. 贝壳找房 OLAP 平台实践

热门文章

  1. modbus调试工具 linux,Modbus TCP的模拟器的Windows/Linux的
  2. 解读正则化 LASSO回归 岭回归
  3. kali初使用之zsh
  4. 第二章 04 魔镜世界
  5. 中国液冷数据中心市场发展研究
  6. AppID、AppKey、AppSecret
  7. 东网科技、Rancher Labs联合发布“容器+虚拟化”双引擎超融合平台HOR
  8. 你们要的网页版matlab来了,速领!
  9. A leaf Variable that requires grad is being used in an in-place operation
  10. Oracle 10G 64位下载