業(yè)務(wù)部門希望現(xiàn)有業(yè)務(wù)系統(tǒng)可以改造成類似OA那樣的流程定制化罗售,當(dāng)時(shí)對(duì)系統(tǒng)的代碼邏輯已有一定了解, 存在下面的一些問題:
- 系統(tǒng)有兩張與工作流相關(guān)的表托慨,卻并沒有實(shí)現(xiàn)一個(gè)流程引擎來統(tǒng)管流程的走向扫皱,代碼內(nèi)直接粗暴的用id值判斷流程埠胖,流程節(jié)點(diǎn)也是直接手寫sql寫進(jìn)數(shù)據(jù)庫.
- 流程相關(guān)的邏輯凌亂间聊,代碼冗余很多
- 耦合度很高族购,代碼幾乎都是一次性的,無法被他處調(diào)用
- 流程邏輯與業(yè)務(wù)邏輯混在一起, 新寫一個(gè)業(yè)務(wù)需求時(shí)往往要花一定精力是書寫流程相關(guān)的邏輯.
針對(duì)現(xiàn)實(shí)情況陵珍,大概有了如下目標(biāo)
- 流程要可配置寝杖,每個(gè)流程節(jié)點(diǎn)有其固定的key來標(biāo)識(shí)它,包括每個(gè)節(jié)點(diǎn)的處理結(jié)果
- 實(shí)現(xiàn)一個(gè)流程引擎來統(tǒng)一管理流程
- 每個(gè)節(jié)點(diǎn)有與之對(duì)應(yīng)的處理類
- 因?yàn)椴糠止?jié)點(diǎn)的跳轉(zhuǎn)并無特殊邏輯互纯,應(yīng)該有一個(gè)默認(rèn)的節(jié)點(diǎn)處理類瑟幕,它只有保存數(shù)據(jù)和提交流程結(jié)果的邏輯
- 在流程引擎處對(duì)每個(gè)節(jié)點(diǎn)的處理過程預(yù)埋幾個(gè)鉤子,這樣要另外加入三方邏輯時(shí)就不必改動(dòng)現(xiàn)有的文件
前端可視化實(shí)現(xiàn)
百度了幾次留潦,最后選定了jsPlumb這款插件收苏,結(jié)合bootstrap、artTemplate最終實(shí)現(xiàn)了如下流程可視化效果:
img1
img2
img3
提交的數(shù)據(jù)格式如下:
{
"workflow_group":"normal",
"conf":{
"node_1":{
"name":"節(jié)點(diǎn)一","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":"節(jié)點(diǎn)二","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":"節(jié)點(diǎn)三","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":"節(jié)點(diǎn)四","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":"業(yè)務(wù)結(jié)束","key":"apply_end","workflow_group":"normal",
"status":{},
"style":{"left":"781px","top":"551px"}
}
}
}
數(shù)據(jù)表部分
三張流程相關(guān)的表愤兵,一張定義流程組,一張定義流程組的節(jié)點(diǎn),一張定義節(jié)點(diǎn)可選的結(jié)果
CREATE TABLE `workflow_group` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '0:監(jiān)聽流程組',
`group_name` varchar(20) NOT NULL COMMENT '流程組名',
`group_key` varchar(20) NOT NULL COMMENT '流程組標(biāo)識(shí)',
`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:監(jiān)聽流程組',
`node_name` varchar(20) NOT NULL COMMENT '節(jié)點(diǎn)名稱',
`node_key` varchar(20) NOT NULL COMMENT '流程節(jié)點(diǎn)標(biāo)識(shí)',
`is_deleted` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否被刪除',
`style` varchar(255) DEFAULT NULL COMMENT '節(jié)點(diǎn)樣式',
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='流程節(jié)點(diǎn)表';
CREATE TABLE `workflow_result` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`workflow_node_id` int(11) unsigned NOT NULL COMMENT '所屬工作流節(jié)點(diǎn)ID',
`result_name` varchar(20) NOT NULL COMMENT '結(jié)論名稱',
`result_key` varchar(20) NOT NULL COMMENT '結(jié)論標(biāo)識(shí)',
`is_deleted` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否被刪除',
`next_node_id` int(11) DEFAULT NULL COMMENT '下一個(gè)流程',
`next_node_key` varchar(20) NOT NULL DEFAULT '' COMMENT '下一個(gè)流程標(biāo)識(shí)'
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='流程節(jié)點(diǎn)結(jié)論表';
流程引擎部分
定義了4個(gè)核心文件如下:
- Workflow.class.php final類
核心方法如下:
public function getConf($workflow_group){} //獲取配置
public function setConf($conf,$workflow_group){} //設(shè)置配置
public function getNodeResults($workflow_key,$workflow_group){} //獲取節(jié)點(diǎn)結(jié)果集
public function getListClass($workflow_key, $uid){}//獲取節(jié)點(diǎn)列表處理類
public function getCommitClass($id, $workflow_key, $uid){}//獲取節(jié)點(diǎn)提交處理類
- WorkflowCommit.class.php abstract類
每個(gè)節(jié)點(diǎn)處理類都繼承于這個(gè)抽象類排吴,要實(shí)現(xiàn)如下兩個(gè)抽象方法:
// 提交處理
abstract protected function _commit($resultKey, array $data);
// 頁面輸出顯示
abstract protected function _output($id);
WorkflowHook.class.php abstract類
每個(gè)節(jié)點(diǎn)的鉤子文件都繼承于這個(gè)類WorkflowList.class.php abstract類
列表類秆乳,主要有以下方法:
public function getTpl(){} // 獲取列表模板
public function getMod(){} // 獲取列表模型
public function listFilter(array &$list){} // 列表數(shù)據(jù)過濾
public function setVars(){} // 設(shè)置模板變量
可以定義一個(gè)空類繼承它,作為默認(rèn)列表類钻哩,特殊節(jié)點(diǎn)則定義節(jié)點(diǎn)列表類繼承它覆蓋相關(guān)方法(基本上只用默認(rèn)類就可以了)
寫的比較粗略, 不附帶具體代碼. 下面是最終流程配置的一個(gè)截圖:
img4