工作流在oa和erp中十分常见,现有成熟的工作流通常是在客户端实现的,web实现工作流的案例十分稀少。要实现web工作流必须要有强大的流程设计器,这里为大家介绍一款基于angular的流程控件,其功能十分强大,可直接开发在线流程设计工具。

流程设计效果如下:

该流程工具使用的是syncfusion旗下的angular组件开发,需要先安装组件: @syncfusion/ej2-angular-diagrams

angular项目中添加demo-flow组件,在demo-flow目录中添加script文件夹,script中粘贴diagram-common.js

准备就绪后开始布局流程页面,布局代码如下:

<script src="script/diagram-common.ts"></script>
<div class="m-portlet m-portlet--mobile">
<div class="m-portlet__head">
<div class="m-portlet__head-caption">
<div class="m-portlet__head-title">
<h3 class="m-portlet__head-text">
流程设计测试
</h3>
</div>
</div>
</div>
<div class="diagram-serialization" style="width: 100%;height: 10%">
<ejs-toolbar width="100%" (clicked)="onClicked($event)">
<e-items>
<e-item text='New' tooltipText='New' prefixIcon='e-ddb-icons e-new'></e-item>
<e-item type='Separator'></e-item>
<e-item text='Save' tooltipText='Save' prefixIcon='e-ddb-icons e-save'></e-item>
<e-item type='Separator'></e-item>
<e-item text='Load' tooltipText='Load' prefixIcon='e-ddb-icons e-open'></e-item>
<e-item type='Separator'></e-item>
</e-items>
</ejs-toolbar>
</div>
<div style="width:100%;height: 80%">
<div id="palette-space" class="sb-mobile-palette">
<ejs-symbolpalette id="symbolpalette" [enableAnimation]='enableAnimation' [expandMode]='expandMode'
[palettes]='palettes' (created)='create($event)' width="100%" height="700px" [symbolHeight]=60
[symbolWidth]=60 [symbolMargin]='symbolMargin' [getSymbolInfo]='getSymbolInfo'
[getNodeDefaults]='getSymbolDefaults'>
</ejs-symbolpalette>
</div> <div id="diagram-space" class="sb-mobile-diagram">
<div class="content-wrapper">
<ejs-diagram #diagram id="diagram" width="100%" height="700px" [snapSettings]='snapSettings'
[getConnectorDefaults]='getConnectorDefaults' (doubleClick)="doubleClick($event)">
<e-nodes>
<e-node id='Start' [height]=50 [width]=100 [shape]='terminator' [offsetX]=250 [offsetY]=80
[style]='terminatorStyle'>
<e-node-annotations>
<e-node-annotation content='Start'>
</e-node-annotation>
</e-node-annotations>
</e-node>
<e-node id='Alarm' [height]=50 [width]=100 [shape]='process' [offsetX]=250 [offsetY]=160
[style]='processStyle'>
<e-node-annotations>
<e-node-annotation content='Alarm Rings'>
</e-node-annotation>
</e-node-annotations>
</e-node>
<e-node id='Ready' [height]=50 [width]=100 [shape]='decision' [offsetX]=250 [offsetY]=240
[style]='decisionStyle'>
<e-node-annotations>
<e-node-annotation content='Ready to Get Up?'>
</e-node-annotation>
</e-node-annotations>
</e-node>
<e-node id='Climb' [height]=50 [width]=100 [shape]='process' [offsetX]=250 [offsetY]=330
[style]='processStyle'>
<e-node-annotations>
<e-node-annotation content='Climb Out of Bed'>
</e-node-annotation>
</e-node-annotations>
</e-node>
<e-node id='End' [height]=50 [width]=100 [shape]='terminator' [offsetX]=250 [offsetY]=430
[style]='terminatorStyle'>
<e-node-annotations>
<e-node-annotation content='End'>
</e-node-annotation>
</e-node-annotations>
</e-node>
<e-node id='Relay' [height]=50 [width]=100 [shape]='delay' [offsetX]=450 [offsetY]=160
[style]='delayStyle'>
<e-node-annotations>
<e-node-annotation content='Relay'>
</e-node-annotation>
</e-node-annotations>
</e-node>
<e-node id='Hit' [height]=50 [width]=100 [shape]='process' [offsetX]=450 [offsetY]=240
[style]='processStyle'>
<e-node-annotations>
<e-node-annotation content='Hit Snooze Button'>
</e-node-annotation>
</e-node-annotations>
</e-node>
</e-nodes>
<e-connectors>
<e-connector id='connector1' sourceID='Start' targetID='Alarm'>
</e-connector>
<e-connector id='connector2' sourceID='Alarm' targetID='Ready'>
</e-connector>
<e-connector id='connector3' sourceID='Ready' targetID='Climb'>
<e-connector-annotations>
<e-connector-annotation content='Yes' [style]='connectorTextStyle'>
</e-connector-annotation>
</e-connector-annotations>
</e-connector>
<e-connector id='connector4' sourceID='Climb' targetID='End'>
</e-connector>
<e-connector id='connector5' sourceID='Ready' targetID='Hit'>
<e-connector-annotations>
<e-connector-annotation content='No' [style]='connectorTextStyle'>
</e-connector-annotation>
</e-connector-annotations>
</e-connector>
<e-connector id='connector6' sourceID='Hit' targetID='Relay'>
</e-connector>
<e-connector id='connector7' sourceID='Relay' targetID='Alarm'>
</e-connector>
</e-connectors>
</ejs-diagram>
</div>
<ejs-uploader #defaultupload id='fileupload' (success)='onUploadSuccess($event)'
[asyncSettings]='asyncSettings'></ejs-uploader>
</div>
</div> <div bsModal #createOrEditModal="bs-modal" class="modal fade" tabindex="-1" role="dialog"
aria-labelledby="createOrEditModal" aria-hidden="true" [config]="{backdrop:'static'}">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title">
<span>修改节点</span>
</h4>
<button type="button" class="close" (click)="close()" attr.aria-label="关闭">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<div class="form-group">
<label>Id</label>
<input type="text" class="form-control" [(ngModel)]="selectItem.id" readonly>
</div>
<div class="form-group" [hidden]="selectItem.type!='node'">
<label>名称*</label>
<input type="text" class="form-control" [(ngModel)]="selectItem.name">
</div>
<div class="form-group" [hidden]="selectItem.type!='node'">
<label>执行权限</label>
<select class="form-control" [formControl]="selectedState">
<option value="">选择执行权限</option>
<option value="1">所有人</option>
<option value="2">指定角色</option>
</select>
</div>
<div class="form-group" [hidden]="selectItem.type!='node' || selectedState.value!='2'">
<label class="m-checkbox">
<input type="checkbox">
部门主管
<span></span>
</label>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<label class="m-checkbox">
<input type="checkbox">
部门经理
<span></span>
</label>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</div>
<div class="form-group" [hidden]="selectItem.type!='connector'">
<label>执行条件</label><br>
<p-radioButton name="radGroup" value="yes" label="通过" [(ngModel)]="condition"></p-radioButton>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<p-radioButton name="radGroup" value="no" label="不通过" [(ngModel)]="condition"></p-radioButton>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<p-radioButton name="radGroup" value="scope" label="执行范围" [(ngModel)]="condition"></p-radioButton>
</div>
<div class="form-row" [hidden]="selectItem.type!='connector' || condition!='scope'">
<div class="form-group col-md-4">
<label>运算符</label>
<select class="form-control" [formControl]="operator">
<option value="">选择运算符</option>
<option value="大于">大于</option>
<option value="小于">小于</option>
<option value="等于">等于</option>
</select>
</div>
<div class="form-group col-md-4">
<label class="">值</label>
<div class="">
<input type="number" [(ngModel)]="scopeValue" class="form-control" placeholder="值">
</div>
</div>
<div class="form-group col-md-4">
<label>单位</label>
<select class="form-control" [formControl]="unit">
<option value="">选择单位</option>
<option value="天">天</option>
<option value="小时">小时</option>
<option value="元">元</option>
</select>
</div>
</div> </div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" (click)="close()">关闭</button>
<button type="button" class="btn btn-primary" (click)="save()">
<i class="fa fa-save"></i><span>保存</span>
</button>
</div>
</div> </div>
</div>
</div>

流程页面模板中加入了双击节点和连接器的事件,如果要开发工作流必须要对事件作处理,仅开发流程设计器则需要取消双击事件以免影响使用。

事件处理如下:

    public doubleClick(args: IDoubleClickEventArgs): void {
var node = this.diagram.selectedItems.nodes[0];
var connector = this.diagram.selectedItems.connectors[0];
if (node) {
this.selectItem.id = node.id;
this.selectItem.name = node.annotations[0].content;
this.selectItem.type = 'node'; this.modal.show();
}
if (connector) {
this.selectItem.id = connector.id;
this.selectItem.name = connector.annotations[0].content;
this.selectItem.type = 'connector';
this.modal.show();
}
} save(): void {
if (this.diagram.selectedItems.nodes[0]) {
this.diagram.selectedItems.nodes[0].annotations[0].content = this.selectItem.name;
this.close();
}
if (this.diagram.selectedItems.connectors[0]) {
if(this.condition=='yes'){
this.diagram.selectedItems.connectors[0].annotations[0].content="通过";
}
if(this.condition=='no'){
this.diagram.selectedItems.connectors[0].annotations[0].content="不通过";
}
if(this.condition=='scope'){
this.diagram.selectedItems.connectors[0].annotations[0].content=this.operator.value+' '+this.scopeValue+' '+this.unit.value;
}
this.close();
}
} close(): void {
this.modal.hide();
}

流程器显示和双击功能如下:

到这里angular的流程设计器已经介绍完毕,要实现工作流机制需要针对自己的系统作表单设计和业务关联,相关的实现文档有很多,这里就不过多介绍了。目前功能还比较粗糙,优化完后我会对这些功能进行开源,感兴趣的可以后续关注。

angular流程引擎集成的更多相关文章

  1. .NET 开源工作流: Slickflow流程引擎高级开发(七)--消息队列(RabbitMQ)的集成使用

    前言:工作流流程过程中,除了正常的人工审批类型的节点外,事件类型的节点处理也尤为重要.比如比较常见的事件类型的节点有:Timer/Message/Signal等.本文重点阐述消息类型的节点处理,以及实 ...

  2. 基于开源流程引擎开发BPM或OA有哪些难点

    前言     如何基于开源流程引擎开发OA系统?开源流程引擎哪个好?把它整合到自己的产品里难不难,有没有啥风险?这是大家经常遇到的问题.笔者从2006年开始参与流程引擎开发,经历了三代流程引擎研发,支 ...

  3. .NET 开源工作流: Slickflow流程引擎高级开发(十) -- BpmnJS流程设计器集成

    前言: 在Slickflow产品开发过程中,前端流程设计器经历了几个不同的版本(jsPlumb, mxGraph等),目的是为了在设计流程时的用户体验更加良好,得到客户的好评和认可.BpmnJS流程设 ...

  4. Fixflow引擎解析(一)(介绍) - Fixflow开源流程引擎介绍

    Fixflow引擎解析(四)(模型) - 通过EMF扩展BPMN2.0元素 Fixflow引擎解析(三)(模型) - 创建EMF模型来读写XML文件 Fixflow引擎解析(二)(模型) - BPMN ...

  5. 从零开始学习和改造activiti流程引擎的13天,自己记录一下

    day#1(11.13) 尝试通过spring boot 集成最新版activiti 7,但是苦于官方的文档基本为空,无法完成spring boot的配置,最终按照activiti 6的文档,手工初始 ...

  6. 关于广州xx公司对驰骋BPM, 流程引擎表单引擎 常见问题解答

    关于广州xx公司对驰骋BPM, 流程引擎表单引擎 常见问题解答 @驰骋工作流,ccflow周朋 周总早, ccflow 功能很强大,在体验过程中,以下几个问题需沟通下: 先使用.net 再使用java ...

  7. 低代码平台--基于surging开发微服务编排流程引擎构思

    前言 微服务对于各位并不陌生,在互联网浪潮下不是在学习微服务的路上,就是在使用改造的路上,每个人对于微服务都有自己理解,有用k8s 就说自己是微服务,有用一些第三方框架spring cloud, du ...

  8. 项目实践之工作流引擎基本文档!Activiti工作流框架中流程引擎API和服务详解

    流程引擎的API和服务 流程引擎API(ProcessEngine API)是与Activiti打交道的最常用方式 Activiti从ProcessEngine开始.在ProcessEngine中,可 ...

  9. 开源流程引擎osworkflow、jbpm、activiti、flowable、camunda哪个好?

    市场上比较有名的开源流程引擎有osworkflow.jbpm.activiti.flowable.camunda.其中:Jbpm4.Activiti.Flowable.camunda四个框架同宗同源, ...

随机推荐

  1. NFS PersistentVolume

    一.部署nfs服务端: k8s-master 节点上搭建了 NFS 服务器 (1)安装nfs服务: yum install -y nfs-utils rpcbind vim /etc/exports ...

  2. Day04:异常处理(二) / 多线程基础

    多线程 线程是什么? 一个线程是线程一个顺序执行流. 同类的多个线程共享一块内存空间和一组系统资源,线程本身有一个供程序执行时的栈堆.线程在切换时负荷小,因此,线程也被称为轻负荷进程.一个进程中可以包 ...

  3. 状态管理之 Flux、Redux、Vuex、MobX(概念篇)

    本文是对 Flux.Redux.Vuex.MobX 几种常用状态管理模式的总结,偏向于概念层面,不涉及过多代码. 状态管理 什么是状态管理? 状态管理就是,把组件之间需要共享的状态抽取出来,遵循特定的 ...

  4. Ruby On Rails 路径穿越漏洞(CVE-2018-3760)

    Ruby On Rails在开发环境下使用Sprockets作为静态文件服务器,Ruby On Rails是著名Ruby Web开发框架,Sprockets是编译及分发静态资源文件的Ruby库. Sp ...

  5. 【VS开发】VC++ 获取系统时间、程序运行时间(精确到秒,毫秒)的五种方法

    1.使用CTime类(获取系统当前时间,精确到秒) CString str; //获取系统时间 CTime tm; tm=CTime::GetCurrentTime();//获取系统日期 str=tm ...

  6. JavaScript校验身份证,包含省份、长度、出生年月日、校验位的检测、性别、年龄

    一.代码如下 let vcity = {11: '北京', 12: '天津', 13: '河北', 14: '山西', 15: '内蒙古', 21: '辽宁', 22: '吉林', 23: '黑龙江 ...

  7. Python smtplib发邮件

    常用邮箱SMTP.POP3域名及其端口号 发送普通文本内容的邮件 import smtplib from email.header import Header from email.mime.text ...

  8. MySQL_数据查询

    目录 1.查看数据的两种方法 2.查看数据并进行筛选(where) 3.不查看重复记录(distinct),空值,非空值 5.查看指定行(limit) 6.模式匹配(like) regexp 6.范围 ...

  9. c++文件指针读写图片文件

    #include "stdafx.h"#include <string>using namespace std;int _tmain(int argc, _TCHAR* ...

  10. FileSystemResource 找不到文件

    环境 Spring 3.2.5.RELEASE 原因 使用 FileSystemResource 加载文件的过程中,发现一个奇怪的现象,路径完全正确,但是找不到文件的情况.可能的原因是文件的路径上有压 ...