参考链接:http://loonapp.com/blog/27/

因工作需要,做了个工作流系统,用于本部门对其他部门提供服务的接口。做之前在网上找了些资料,也研究了django的一个工作流框架:django-workflow。但感觉很不好用,不是很灵活。于是按照自己的理解自己做了。思路如下:

术语定义如下:

    工单:具体的待处理事项,用户新建的是工单,工单按照工作流的设计来实现不同状态不同处理人之间的流转

    工作流:即工作流的设计,定义了工单的审批链、各状态的处理人、各状态可以执行的操作(提交、保存,处理完成,退回,关闭等等)、每个状态下显示哪些字段、哪些字段可以在哪些编辑。

    工作流处理过程可以理解为工单状态的变化,如一个工作流处理过程中可以有:发起人新建中、发起人编辑中、部门经理审核中、技术人员处理中、发起人验证中、结束等状态,每个状态对应相应的处理人(如部门经理审核中这个状态下只有部门经理才可以处理该工单)。如用户在新建工单的时候处于“发起人新建中”,(用户)提交后工单处于“部门经理审核中”, 部门经理(即“部门经理审核中”状态的处理人)审批通过后,工单的状态变更为“技术人员处理中”。

 

于是可以设计表结构如下:

1、工单表(myworkflowjob):字段可以包括 标题、创建人、当前处理人,创建时间、详细信息、等,  然后与设计的工作流关联:"工作流"字段

2、工作流表(myworkflow):字段包括工作流名称、描述、流程图、提醒方式(短信、邮件、短信+邮件、不提醒等等)、初始状态

3、工作流状态表(myworkflowsstate):字段包括状态名称、该状态下的处理人类型(如部门、个人,角色,职位等等)、具体的处理人(如类型为部门,那么就可以为财务部,行政部等等。如为个人那就是具体的人名字),工单接单方式(主动接单、系统随机分配)、是否为最终状态、关联的工作流

4、工单流转表(myworkflowtran): 字段包括名称(即操作名称:如提交、保存、退回、关闭等)、初始状态、目标状态

5、日志表(myworkflowdisposelog):用于记录处理人各种操作,字段可包括:操作名称、时间、处理意见。

6、工单查看页面表单的展现表(myworkflowdisplayfield):用于定义工单查看时表单中显示哪些字段,字段包括:工作流(myworkflow_id)、字段名

7、工单处理页面状态字段表(myworkflowstatefield):用于用户处理工单时候页面总显示那些字段。字段包括:状态(myworkflowsstate_id)、字段名、读写权限(只读、可编辑)

8、工单类型与工作流关联表(myworkflowtype):用于不同工单类型与工作流的关联。达到用户选择不同类型的工单后系统对其使用相应的工作流及相应的表单。字段包括名称、上级类型、工作流(myworkflow_id)

 

本项目组多工作流使用一个工单表。所以初始化需要将必要的字段都写到该表中

 

新建(配置)工作流思路:

新建工作流名称(表myworkflow)-->添加状态、该状态下的处理表单要显示的字段及是否可以编辑(表myworkflowsstate)--->设置初始状态(表myworkflow)---->设置工单流转(即工单流转表myworkflowtran)

设置工单类型(请假、监控处理、权限申请等等)与工作流之间的关联即表myworkflowtype

 

工单处理逻辑:

1、在新建工单的页面中,用户选择工单类型,后台根据“工单类型与工作流关联”的表来确定使用的工作流

2、根据确定的工作流弹出工单信息输入界面(内容包括标题、详细信息、附件等等,具体表单字段通过改工作流的初始状态来确定),根据工作流的初始状态查找状态表来确定可以执行的操作(提交、保存,处理完成,退回,关闭等),将这些操作作为该界面的按钮,用户填写完工单基本信息后点击相应的操作按钮,来实现状态的流转。后台结合前端提交的数据并生成工单必备的字段信息(工单创建时间、创建人、流水号等),将这些信息写到工单表里。其中当前状态、当前处理人通过工单流转表和状态表来确定 用户执行相应操作后导致的属性变化

3、通过步骤2中插入到工单表中的数据“处理人类型”、“当前处理人”来确定哪些人有权限处理这些工单。 如果处理人类型不是“个人”,那就根据这条数据中的“当前状态“来确定接单方式,主动接单(有权限的人先执行接单操作将当前处理人变更为自己再处理),系统随机分配(后台在执行状态流转时随机设置工单当前处理人为符合条件的某一个人)

4、查看工单的界面通过 “工单查看页面表单的展现表”来确定 显示哪些字段

5、处理工单的界面通过“工单处理页面表单的展现表” 来确定显示哪些字段,以及哪些字段可以在处理过程中再次修改

 

 

效果图

image.png

鉴于评论很多要求model。下面贴几个示例, 模型名称上与上面说明的有些不同(2017-10-10)

class MyWorkflow(models.Model):
    """
    流程控制
    """
    name = models.CharField(u'流程名称', max_length=100, unique=True)
    initial_state_id = models.IntegerField(u'初始状态', blank=True, null=True, unique=True)
    notice_type = models.IntegerField(u'通知方式', default=1)  # 1.邮件 2.短信 3.钉钉 4.邮件+钉钉 8.无
    workflow_diagram_name = models.CharField(u'流程图', max_length=50)  # 流程图名. 保存路径在media/workflowdiagram/
    field_list_str = models.TextField(u'字段', blank=True, null=True)   # json格式 ['name', 'desc']
    desc = models.CharField(u'备注', max_length=50, blank=True)
    desc_template = models.TextField(u'工单详细内容模板', default='', blank=True)
 
    gmt_created = models.DateTimeField(u'创建时间', auto_now_add=True)
    gmt_modified = models.DateTimeField(u'修改时间', auto_now=True)
    is_deleted = models.BooleanField(u'已删除', default=False)
 
    def __unicode__(self):
        return u"%s" % self.name
 
    class Meta:
        verbose_name = '工作流'
        verbose_name_plural = '工作流'
         
         
class State(models.Model):
    """
    流程状态
    """
    name = models.CharField(u'名称', max_length=30)
    deliver_type = models.IntegerField(u'流转类型', default=1)  # 1.正常流转,2.自动流转,3.脚本流转
    my_workflow_id = models.IntegerField(u'工作流id')  # 关联的工作流的id
    participant_type = models.IntegerField(u'参与者类型')  # 1.个人 2.职位 3.部门 4.角色 5.变量 6.多人 9.bot
    is_end_state = models.BooleanField(u'是否为最终状态')
    participant = models.CharField(u'参与者', max_length=30)  # 可以为username\多个username(以,隔开)\部门id\角色id\变量id等
    distribute_type = models.IntegerField(u'接单方式', default=1)  # 1主动接单,2.随机分配,3.全部处理(要求所有参与人都要处理一边)
    state_filed_str = models.TextField(u'表单字段')  # json格式存储,包括读写属性1:只读,2:必填,3:可选,4:不显示, 字典的字典
    task_dict_info = models.TextField(u'任务信息')  # json格式存储,[{'task_name':'a', 'arguments':[1,2]},{'task_name':'b', 'arguments':[3,4]}]
 
    is_skiped = models.IntegerField(u'是否支持跳过当前处理状态', default=0) # 是否支持跳过当前处理状态
    auto_flow_condition = models.IntegerField(u'自动跳过条件', null=True) # 1: '创建人等于leader审批人'
    AUTO_FLOW_CONDITION = [('当前处理人等于工单创建人', 1),
                           ('无需执行sql', 2),
                           ('发起人属于特定部门', 3),
                            
    auto_flow_destination = models.IntegerField(u'自动跳过目标状态id', null=True)
    dept = models.ForeignKey(MyDept, verbose_name=u'部门', related_name="state_dept", null=True, blank=True)
    TIMER_UNIT = [('分', 1), ('时', 2), ('天', 3)]
    timer_unit = models.IntegerField(u'定时器单位', null=True, default=None)
    timer_value = models.IntegerField(u'定时器值', null=True, default=None)
    timer_destination = models.IntegerField(u'定时自动跳过目标状态id', null=True, default=None)
    sub_work_flow = models.ForeignKey(MyWorkflow, verbose_name=u'子工作流', related_name='State_workflow', null=True, blank=True, help_text="")
 
    gmt_created = models.DateTimeField(u'创建时间', auto_now_add=True)
    gmt_modified = models.DateTimeField(u'修改时间', auto_now=True)
    is_deleted = models.BooleanField(u'已删除', default=False)
 
    def __unicode__(self):
        return u"%s" % self.name
 
    class Meta:
        verbose_name = '工作流状态'
        verbose_name_plural = '工作流状态'
        
         
class Transition(models.Model):
    """
    工作流流转
    """
    name = models.CharField(u'操作', max_length=50)
    my_workflow_id = models.IntegerField(u'工作流id')
    source_state_id = models.IntegerField(u'原状态id')
    dest_state_id = models.IntegerField(u'目标状态id')
    is_alert = models.BooleanField(u'点击是否提示')
    alert_text = models.CharField(u'点击提示内容', max_length=100, null=True, blank=True)
 
    gmt_created = models.DateTimeField(u'创建时间', auto_now_add=True)
    gmt_modified = models.DateTimeField(u'修改时间', auto_now=True)
    is_deleted = models.BooleanField(u'已删除', default=False)
 
    def __unicode__(self):
        return u"%s" % self.name
 
    class Meta:
        verbose_name = '状态流转'
        verbose_name_plural = '状态流转'

后记: 本工作流后续又做了次重构, 目前我正在着手新的开源版本的开发,计划是今年底开源, 会做很多通用性改进。 主要包括:

1.       支持灵活新增工单字段(目前需要修改模型)

2.       脚本流转时 脚本支持灵活的自定义(目前新增脚本需要修改代码, 新版将支持编写脚本后上传到系统直接使用)

3.       支持多条件流转(如作为报销工单时 金额区间在0-1000、1000-10000, 10000-5000, 50000+ 使用不同的审批流、不同的审批人)

4.       支持更多的开放api(可以只作为工单引擎使用,不使用本系统的界面)

5.       其他性能优化,界面优化等等

如果你对开源进展感兴趣,请在留言区留下你的邮箱,我会在开源后联系你

 

-----------------进度更新----------------------

开源版本即将发布(预计2018年5月底)。https://github.com/blackholll/loonflow  最新代码在develop分支,正式版本再tag(如果已经发布的话)

--- 20180503

 

开源版本已发布:https://github.com/blackholll/loonflow/releases

---20180529

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐