介绍一个真正符合中国国情的工作流设计参考(包括PHP实现)
开源的工作流很少有让人满意的,即便是国内用的比较多的jbpm,用起来也会觉得很便扭。再加上PHP中没有什么好用的工作流,于是干脆自己设计一个,设计的原则如下:
1 根据80/20原则,只使用wfmc模型中最符合自身应用的20%功能
2 充分吸收国内使用jbpm开发BOSS中遇到的问题,工作流引擎只负责参数的收集和流程的流转,具体和业务的控制,交给每个流程定制的控制类去实现。
3 表单采用简单的html 控制标签的方法实现
4 权限和模板引擎,以及其它辅助函数直接使用办公系统自带的框架
5 充分利用PHP语言的特点,流程设计是基于数据库的,程序上使用OO设计,但采用重对象的方法
6 不把可视化设计流程的工作交给最终客户,而且由设计时完成,因此不考虑流程版本更新的问题
一、工作流数据表设计
tbl_workflow_defination:工作流定义表
|
流程id | ||||||||||
defination_name | 流程名称 | ||||||||||
defination_handler | 流程处理辅助文件,每个工作流一个文件 | 自定义处理文件,及其对象。例如workflow-proporsal-handler.php,其中定义对象proposal |
tbl_workflow_node:流程结点步骤表
node_id |
结点id |
|
defination_id |
流程id |
|
node_index |
结点序号 |
结点的step |
node_name |
结点名称 |
|
node_type |
结点类型 |
1人为决策,2自动处理(直接执行execute_function),3等待外部响应(例如外部WS触发),4分支,5汇总 6结束结点(此结点执行时候自动终止进程) |
init_function |
流程初始函数 |
|
run_function |
流程运行函数 |
|
save_function |
流程保存函数 |
|
transit_function |
流程流转函数 |
|
prev_node_index |
前结点序号 |
例如1。开始结点没有 执行前,通过此来校验一下流程 |
next_node_index |
后结点序号 |
例如[同意]3,[不同意]4。尾结点或要结束的结点没有,若没有,直接调用end |
executor |
执行角色,组,人 |
role[1,2] group[1,2] user[1,2],为空由运行时决定 |
execute_type |
执行类型 |
0需所有人执行 1只需一人执行 |
remind |
提醒 |
0不提醒 1邮件 2短信 3邮件和短信 |
field |
可编辑的字段 |
name,content |
max_day |
最长时间(天) |
|
tbl_workflow_process:流程执行进程表
process_id |
进程id |
|
defination_id |
流程id |
|
process_desc |
进程描述 |
显示在我的工作台中 |
context |
上下文 |
存放上下文变量,例如业务表的id |
current_node_index |
当前结点序号 |
|
start_time |
流程启动时间 |
如遇分支、汇合显示为: 1=》3,4=》3,5=》6 |
finish_time |
流程完成时间 |
|
state |
状态 |
1运行 2结束 |
start_user |
发起人 |
发起人,用于显示自己的流程 |
tbl_workflow_thread :流程执行线程表
thread_id |
线程id
|
|
|||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
process_desc | 进程描述 | ||||||||||||||||||||||||||||||||||||
node_id | 结点id | ||||||||||||||||||||||||||||||||||||
node_name | 结点名称 | ||||||||||||||||||||||||||||||||||||
执行人 | 执行人 | ||||||||||||||||||||||||||||||||||||
start_time | 线程生成时间 | ||||||||||||||||||||||||||||||||||||
receive_time | 线程接收时间 | ||||||||||||||||||||||||||||||||||||
finish_time | 线程完成时间 | ||||||||||||||||||||||||||||||||||||
max_time | 结点规定的最长时间 | ||||||||||||||||||||||||||||||||||||
状态 | 状态 | 0未接收 1已接收 2已处理 |
领导传阅 |
部门领导肋 |
填写表单 |
结束 |
放弃 |
提交 |
同意 |
重填(退回) |
不同意 |
完成 |
外部响应
发送支付信息 |
接收支付成功响应(外部WS触发该流程) |
三、PHP设计
运行的函数由结点在设计时候决定,如果没有设定,就使用默认的函数。利用了PHP语言的以下特性
<?php class Foo { function Variable() { $name = 'Bar'; $this->$name(); // This calls the Bar() method } function Bar() { echo "This is Bar"; } } $foo = new Foo(); $funcname = "Variable"; $foo->$funcname(); // This calls $foo->Variable() ?>
使用前可以用method_exists来检查
WorkflowService.php
WorkflowService
$defination
$process
$node
$thread
$input 用户输入的和流程有关的变量
list_defination()
{
}
init_process(defination_id)
{ global user;
取得$defination,得到业务的handler,例如WorkflowProposalHandler
建立$process行记录
}
start_process()
{ 调用WorkflowProposalHandler->start($process)//新建业务对象,并把业务类的参数例如proposal_id放到$process[‘context’]里面
init_thread(1); //默认调用第一个结点
}
list_ my_thread ()
{ global user;
}
init_thread(node_index)
{
取得$node
取得$process
修改$process为运行到当前结点
Switch($node[‘node_type’])
Case 1: 人工决策
建立$thread
WorkflowProposalHandler-> init_function ($process,$node,$thread)
发送提醒
Case 2: 自动处理
建立$thread
WorkflowProposalHandler-> init_function ($process,$node,$thread)
调用run_thread(thread_id)
Case 3: 等待外部响应
建立$thread
WorkflowProposalHandler-> init_function ($process,$node,$thread)
Case 4: 分支
取得所有分支的子结点
init_thread(子结点)
Case 5: 汇总:
取得所有前结点,如果所有前结点的Thread都结束了,调出下一结点
调用init_thread(子结点)
Case 6: 结束:直接结束进程process
end_process()
}
run_thread(thread_id)
{
取得$node
取得$process
取得$thread
Switch($node[‘node_type’])
Case 1: 人工决策
修改$thread为已接收
WorkflowProposalHandler-> run_function ($process,$node,$thread)显示表单
Case 2: 自动处理
修改$thread为已接收
$next_node_id=WorkflowProposalHandler-> run_function ($process,$node,$thread)
调用transit_thread(thread_id, $next_node_id)
Case 3: 等待外部响应
修改$thread为已接收
$next_node_id=WorkflowProposalHandler-> run_function ($process,$node,$thread)
transit_thread(thread_id, $next_node_id)
Case 4: 分支
Case 5: 汇总:
Case 6: 结束:
}
save_thread(thread_id)
{ //保存结点数据
取得$node
取得$process
取得$thread
Switch($node[‘node_type’])
Case 1: 人工决策
WorkflowProposalHandler-> save_function ($process,$node,$thread)保存表单
WorkflowProposalHandler-> run_function ($process,$node,$thread)显示表单
Case 2: 自动处理
Case 3: 等待外部响应
Case 4: 分支
Case 5: 汇总:
Case 6: 结束:
}
transit_thread(thread_id, $next_node_id)
{ 取得$node
取得$process
取得$thread
Switch($node[‘node_type’])
Case 1: 人工决策
WorkflowProposalHandler->transit_function($process,$node,$thread,$next_node_id)
修改$thread为已完成
If($next_node_id < $ cur_node_id) { //回退
删除所有大于$next_node_id的Thread
}
init_thread($next_node_id)
Case 2: 自动处理
修改$thread为已完成
If($next_node_id < $ cur_node_id) { //回退
删除所有大于$next_node_id的Thread
}
init _thread($next_node_id)
Case 3: 等待外部响应
修改$thread为已完成
If($next_node_id < $ cur_node_id) { //回退
删除所有大于$next_node_id的Thread
}
init _thread($next_node_id)
Case 4: 分支
Case 5: 汇总:
Case 6: 结束:
}
end_process()
list_my_process
view_process
workflow_proposal_handler.php
WorkflowProposalHandler
start()
prepare_input() 准备用户输入变量,从$_POST收集
init_function () 线程建立后调用的默认函数,当流程的执行者由程序生成时,在此函数内更改$thread的executor,例如直接赋值user[2]
run_function () 线程运行化时候调用的默认函数
save_function () 保存运行信息
transit_function ()执行流转
sendmail 其它结点调用函数
workflow.php
switch(op)
case list_defination
参数:无
WorkflowService->list_defination()
case start_process :启动
参数:defination_id
WorkflowService->init_process(defination_id)
WorkflowService->start_process()
case list_ my_thread :待处理的列表
WorkflowService->list_ my_thread()
case run_thread :
参数:thread_id
WorkflowService->run_thread(thread_id)
case save_thread :
参数:thread_id
把input收集起来(所有的变量以 f_开头),赋给WorkflowService的Input,另外还要获得thread_id
WorkflowService->save_thread(thread_id)
case transit_thread :
参数:thread_id
把input收集起来,赋给WorkflowService的Input,另外还要获得thread_id
$next_node_id = 得到用户选择的下一结点id
WorkflowService-> transit _thread(thread_id,$next_node_id)
case list_my_process:所有我发起的流程
case list_all_process:所有我发起的流程
case view_process :
在其它程序中初始化流程
1先自行建立好业务表单
2WorkflowService->init_process(defination_id)
3把建好的业务表单的ID放在process的context里面
4WorkflowService->init_thread(1)
WorkflowService->transit_thread(1,2)通过手动调用把前面的流程过掉
外部服务继续流转流程(只用于自动流程)
1 把input收集起来,赋给WorkflowService的Input,另外还要获得thread_id
2 WorkflowService->run_thread(thread_id)
相关文章:

热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

Video Face Swap
使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热门文章

热工具

记事本++7.3.1
好用且免费的代码编辑器

SublimeText3汉化版
中文版,非常好用

禅工作室 13.0.1
功能强大的PHP集成开发环境

Dreamweaver CS6
视觉化网页开发工具

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

随着互联网应用的普及,网站响应速度越来越成为用户关注的重点。为了快速响应用户的请求,网站往往采用缓存技术缓存数据,从而减少数据库查询次数。但是,缓存的过期时间对响应速度有着重要影响。本文将对控制缓存失效时间的方法进行探讨,以帮助PHP开发者更好地应用缓存技术。一、什么是缓存失效时间?缓存失效时间是指缓存中的数据被认为已经过期的时间。它决定了缓存中的数据何时需

如何使用PHP实现文件转换和格式转换功能1.引言在开发Web应用程序过程中,我们经常需要实现文件转换和格式转换的功能。无论是将图片文件转换为其他格式,还是将文本文件从一种编码转换为另一种编码,这些操作都是常见的需求。本文将介绍如何使用PHP实现这些功能,并附带代码示例。2.文件转换2.1将图片文件转换为其他格式在PHP中,我们可以使用

PHP数据缓存的一致性哈希算法实现原理一致性哈希算法(ConsistentHashing)是一种常用于分布式系统中数据缓存的算法,可以在系统扩展和缩减时,最小化数据迁移的数量。在PHP中,实现一致性哈希算法可以提高数据缓存的效率和可靠性,本文将介绍一致性哈希算法的原理,并提供代码示例。一致性哈希算法的基本原理传统的哈希算法将数据分散到不同的节点上,但当节点

如何使用PHP实现移动端适配和响应式设计移动端适配和响应式设计是现代网站开发中重要的实践,它们能够保证网站在不同设备上的良好展示效果。在本文中,我们将介绍如何使用PHP实现移动端适配和响应式设计,并附带代码示例。一、理解移动端适配和响应式设计的概念移动端适配是指根据设备的不同特性和尺寸,针对不同的设备提供不同的样式和布局。而响应式设计则是指通过使用

PHP实现的在线投票系统的用户隐私保护随着互联网的发展和普及,越来越多的投票活动开始转移到在线平台上进行。在线投票系统的便利性给用户带来了很多好处,但同时也引发了用户隐私泄露的担忧。隐私保护已经成为在线投票系统设计中的一个重要方面。本文将介绍如何使用PHP编写一个在线投票系统,并重点讨论用户隐私保护的问题。在设计和开发在线投票系统时,需要遵循以下几个原则来保

如何利用PHP实现用户注册功能在现代的网络应用程序中,用户注册功能是一个非常常见的需求。通过注册功能,用户可以创建自己的账户并使用相应的功能。本文将通过PHP编程语言来实现用户注册功能,并提供详细的代码示例。首先,我们需要创建一个HTML表单,用于接收用户的注册信息。在表单中,我们需要包含一些输入字段,如用户名、密码、邮箱等。可以根据实际需求自定义表单字段。

随着微信小程序的不断发展,越来越多的用户开始选择微信小程序进行登陆。为了提高用户的登录体验,微信小程序开始支持指纹登陆。在本文中,我们将会介绍如何使用PHP来实现微信小程序的指纹登陆。一、了解微信小程序的指纹登陆在微信小程序的基础上,开发者可以使用微信的指纹识别功能,让用户通过指纹登陆微信小程序,从而提高登录体验的安全性和便捷性。二、准备工作在使用PHP实现

美图自研的大模型3.0已经正式发布!并且全面应用于美图旗下影像与设计产品。图片这是自美图大模型面世100天后的最新迭代。相较于最初版本,3.0版能够生成更加真实细腻的画面细节。图片如上这些生成能力,在美图秀秀上能直接体验。图片最近正流行的AIGC玩法,在其中都能找到。图片美图公司的创始人、董事长兼CEO吴欣鸿透露,目前美图的大部分产品都已经融入了自己研发的大模型除了影像和设计领域,美图自研大模型还将在电商、广告、游戏、动漫、影视五大行业发力。美图秀秀可直接体验美图自研大模型名叫MiracleVi
