php开发业务工作流的设计小结

业务部门希望现有业务系统可以改造成类似OA那样的流程定制化,当时对系统的代码逻辑已有一定了解, 存在下面的一些问题:

  • 系统有两张与工作流相关的表,却并没有实现一个流程引擎来统管流程的走向,代码内直接粗暴的用id值判断流程,流程节点也是直接手写sql写进数据库.
  • 流程相关的逻辑凌乱,代码冗余很多
  • 耦合度很高,代码几乎都是一次性的,无法被他处调用
  • 流程逻辑与业务逻辑混在一起, 新写一个业务需求时往往要花一定精力是书写流程相关的逻辑.

针对现实情况,大概有了如下目标

  • 流程要可配置,每个流程节点有其固定的key来标识它,包括每个节点的处理结果
  • 实现一个流程引擎来统一管理流程
  • 每个节点有与之对应的处理类
  • 因为部分节点的跳转并无特殊逻辑,应该有一个默认的节点处理类,它只有保存数据和提交流程结果的逻辑
  • 在流程引擎处对每个节点的处理过程预埋几个钩子,这样要另外加入三方逻辑时就不必改动现有的文件

前端可视化实现

百度了几次,最后选定了jsPlumb这款插件,结合bootstrap、artTemplate最终实现了如下流程可视化效果:


img1

img2

img3

提交的数据格式如下:

{
    "workflow_group":"normal",
    "conf":{
        "node_1":{
            "name":"节点一","key":"node_1","workflow_group":"normal",
            "status":{
                "pass":{"key":"pass","name":"通过","apply_step":"2","next_workflow_key":"node_2"},
                "visit":{"key":"visit","name":"考察","apply_step":"2","next_workflow_key":"node_3"}
            },
            "style":{"left":"407px","top":"354px"}
        },
        "node_2":{
            "name":"节点二","key":"node_2","workflow_group":"normal",
            "status":{
                "pass":{"key":"pass","name":"通过","apply_step":"3","next_workflow_key":"node_4"}
            },
            "style":{"left":"609px","top":"356px"}
        },
        "node_3":{
            "name":"节点三","key":"node_3","workflow_group":"normal",
            "status":{
                "back":{"key":"back","name":"退回","apply_step":"99","next_workflow_key":"node_1"},
                "pass":{"key":"pass","name":"通过","apply_step":"","next_workflow_key":"node_2"}
            },
            "style":{"left":"513px","top":"501px"}
        },
        "node_4":{
            "name":"节点四","key":"node_4","workflow_group":"normal",
            "status":{
                "back":{"key":"back","name":"退回","apply_step":"2","next_workflow_key":"node_3"},
                "pass":{"key":"pass","name":"通过","apply_step":"4","next_workflow_key":"apply_end"}
            },
            "style":{"left":"816px","top":"359px"}
        },
        "apply_end":{
            "name":"业务结束","key":"apply_end","workflow_group":"normal",
            "status":{},
            "style":{"left":"781px","top":"551px"}
        }
    }
}

数据表部分

三张流程相关的表,一张定义流程组,一张定义流程组的节点,一张定义节点可选的结果

CREATE TABLE `workflow_group` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '0:监听流程组',
  `group_name` varchar(20) NOT NULL COMMENT '流程组名',
  `group_key` varchar(20) NOT NULL COMMENT '流程组标识',
  `enable` tinyint(1) NOT NULL DEFAULT '1' COMMENT '是否可用',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='流程组表';

CREATE TABLE `workflow_node` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `workflow_group_id` int(11) unsigned NOT NULL COMMENT '流程组ID,0:监听流程组',
  `node_name` varchar(20) NOT NULL COMMENT '节点名称',
  `node_key` varchar(20) NOT NULL COMMENT '流程节点标识',
  `is_deleted` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否被删除',
  `style` varchar(255) DEFAULT NULL COMMENT '节点样式',
  PRIMARY KEY (`id`),
  UNIQUE KEY `workflow_group_id` (`workflow_group_id`,`node_key`),
  CONSTRAINT `workflow_node_ibfk_1` FOREIGN KEY (`workflow_group_id`) REFERENCES `workflow_group` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='流程节点表';

CREATE TABLE `workflow_result` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `workflow_node_id` int(11) unsigned NOT NULL COMMENT '所属工作流节点ID',
  `result_name` varchar(20) NOT NULL COMMENT '结论名称',
  `result_key` varchar(20) NOT NULL COMMENT '结论标识',
  `is_deleted` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否被删除',
  `next_node_id` int(11) DEFAULT NULL COMMENT '下一个流程',
  `next_node_key` varchar(20) NOT NULL DEFAULT '' COMMENT '下一个流程标识'
  PRIMARY KEY (`id`),
  UNIQUE KEY `workflow_id` (`workflow_node_id`,`result_key`),
  CONSTRAINT `workflow_result_ibfk_1` FOREIGN KEY (`workflow_node_id`) REFERENCES `workflow_node` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='流程节点结论表';

流程引擎部分

定义了4个核心文件如下:

  • Workflow.class.php final类
    核心方法如下:
public function getConf($workflow_group){}  //获取配置
public function setConf($conf,$workflow_group){} //设置配置
public function getNodeResults($workflow_key,$workflow_group){} //获取节点结果集
public function getListClass($workflow_key, $uid){}//获取节点列表处理类
public function getCommitClass($id, $workflow_key, $uid){}//获取节点提交处理类
  • WorkflowCommit.class.php abstract类
    每个节点处理类都继承于这个抽象类,要实现如下两个抽象方法:
// 提交处理
abstract protected function _commit($resultKey, array $data);
// 页面输出显示
abstract protected function _output($id);
  • WorkflowHook.class.php abstract类
    每个节点的钩子文件都继承于这个类

  • WorkflowList.class.php abstract类
    列表类,主要有以下方法:

public function getTpl(){} // 获取列表模板
public function getMod(){} // 获取列表模型
public function listFilter(array &$list){} // 列表数据过滤
public function setVars(){} // 设置模板变量

可以定义一个空类继承它,作为默认列表类,特殊节点则定义节点列表类继承它覆盖相关方法(基本上只用默认类就可以了)

写的比较粗略, 不附带具体代码. 下面是最终流程配置的一个截图:

img4
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,117评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,328评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,839评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,007评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,384评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,629评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,880评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,593评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,313评论 1 243
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,575评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,066评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,392评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,052评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,082评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,844评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,662评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,575评论 2 270

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,100评论 18 139
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 170,569评论 25 707
  • 昨天,妻子参加亲戚家娶媳妇的婚宴回来,大发感慨,说没有想到,亲戚家初中毕业的儿子竟然娶了一个名牌大学毕业的美女,而...
    医涂漫阅读 466评论 1 4
  • 观晚霞·感 苍穹一啸夕霞边, 似幻如梦痴笑间。 蝠飞燕横长空破, 浪迹四海不作仙。 8.1 体育场 天气不算好,...
    清风隐月阅读 104评论 0 0
  • ## 测试
    雨前阅读 62评论 0 0