django+vue3实现流程

965 阅读5分钟

引言

最近因工作需求,需要写一个流程审批业务。

需求

当申请人在网页上完成申请单的填写并提交后,该申请单将自动流转至申请人所在部门的负责人进行审批。部门负责人将根据申请单所提供的信息,决定批准或者退回申请。

一旦部门负责人审批通过,申请单将继续流转至下一环节,届时将由其他同事根据审批结果和既定流程进行后续的处理或协作。

需求分解

想要实现这么一个功能。主要有俩大模块,分别是申请单和流程设计。

申请单:用户处理的就是申请单,申请单按照流程的设计来实现不同节点不同处理人之间的流转

流程:定义了申请单的审批链、各节点的处理人、各节点可以执行的操作(审批、退回)

表设计

申请单:申请单编号、申请单状态、创建时间、其他详细信息等,还需关联当前处理人、申请人、流程、当前节点

流程:流程名称、流程key等

流程节点:节点名称、节点顺序、节点处理人、审批类型(或签、会签)等,还需关联流程

流程流转:流转名称(即:提交、保存、退回、关闭)、源节点、目标节点等,还需关联流程

申请单流转日志:流转名称、审批意见、处理人等,还需关联申请单、当前节点

django model设计

class CellApplyForm(CoreModel,SoftDeleteModel):
    app_number =  models.CharField(max_length=64, null=True, blank=True, verbose_name="申请单编号", help_text="申请单编号")
    test_number =  models.CharField(max_length=64,null=True, blank=True, verbose_name="测试编号", help_text="测试编号")
    handler =  models.CharField(max_length=32,null=True, blank=True, verbose_name="当前处理人", help_text="当前处理人")
    isSubmit =  models.BooleanField(default=True, verbose_name="提交or保存", help_text="提交or保存")
    important = models.CharField(max_length=16, null=True, blank=True, verbose_name="紧急程度", help_text="紧急程度")
    status = models.CharField(max_length=16, null=True, blank=True, verbose_name="申请单状态(被驳回rejected,待提交created,待审核approve,测试中testing,已归档completed)", help_text="申请单状态")
    test_type = models.CharField(max_length=16, null=True, blank=True, verbose_name="测试类型(电芯cell、材料material、电池pack)", help_text="测试类型")
    
    flow_node = models.ForeignKey(FlowNode,null=True, blank=True,related_name="cell_flow_node", on_delete=models.CASCADE, verbose_name='当前节点')
    flow = models.ForeignKey(Flow,null=True, blank=True, on_delete=models.CASCADE, related_name="cell_flow",verbose_name='流程名称')  
    apply_user = models.ForeignKey(Users, related_name="apply_user", on_delete=models.CASCADE, db_constraint=False,
                              verbose_name="关联申请人", help_text="关联申请人")
    handle_user = models.ManyToManyField(to=Users, related_name="handle_user",blank=True, db_constraint=False,
                                         verbose_name="当前处理人", help_text="当前处理人")
    class Meta:
        db_table = table_prefix + "cell_apply_form"
        verbose_name = "电芯测试申请单"
        verbose_name_plural = verbose_name
        ordering = ("-create_datetime",)
        
class Flow(CoreModel,SoftDeleteModel):
    name = models.CharField(max_length=64, verbose_name="流程名称", help_text="流程名称")
    key = models.CharField(max_length=64, default='xx',unique=True, verbose_name="流程key", help_text="流程key")
    sort = models.IntegerField(default=1, verbose_name="流程顺序", help_text="流程顺序")
    status = models.BooleanField(default=True, verbose_name="流程状态", help_text="流程状态")

    class Meta:
        db_table = table_prefix + "flow"
        verbose_name = "流程表"
        verbose_name_plural = verbose_name
        ordering = ("sort",)

class FlowNode(CoreModel,SoftDeleteModel):
    flow = models.ForeignKey(Flow, on_delete=models.CASCADE, related_name="flowNodes",verbose_name='流程名称')  # 外键关联所属流程
    name = models.CharField(max_length=64, verbose_name="节点名称", help_text="节点名称")
    sort = models.IntegerField(default=0, verbose_name="节点顺序", help_text="节点顺序")
    status = models.BooleanField(default=True, verbose_name="节点状态", help_text="节点状态")
    NODE_TYPE_CHOICES = (
        (0, '普通节点'),
        (1, '初始节点'),
        (2, '结束节点')
    )
    node_type = models.IntegerField(choices=NODE_TYPE_CHOICES,default=0,verbose_name='节点类型',help_text='节点类型')
    PARTICIPANT_TYPE_CHOICES = (
        (0, '无处理人'),
        (1, '用户'),
        # (2, '部门'),
        # (3, '角色'),
    )
    participant_type = models.IntegerField(default=0, choices=PARTICIPANT_TYPE_CHOICES, verbose_name='参与者类型')
    participant = models.ManyToManyField(to=Users, related_name='users', blank=True, db_constraint=False,
                                         verbose_name="目标用户", help_text="目标用户")
    APPROVAL_TYPE_CHOICES = (
        (0, '或签'),
        (1, '会签'),
    )
    approval_type = models.IntegerField(default=0, choices=PARTICIPANT_TYPE_CHOICES, verbose_name='审批类型')
    
    class Meta:
        db_table = table_prefix + "flow_node"
        verbose_name = "流程节点表"
        verbose_name_plural = verbose_name
        ordering = ("sort",)
        
class FlowTransition(CoreModel,SoftDeleteModel):
    flow = models.ForeignKey(Flow, on_delete=models.CASCADE, related_name="flowTransitions",verbose_name='流程名称')  # 外键关联所属流程
    NAME_CHOICES = (
        (0, '保存'),
        (1, '审批通过'),
        (2, '驳回'),
        (3, '撤销'),
    )
    name = models.IntegerField(default=1, choices=NAME_CHOICES, verbose_name='流转名称',help_text='流转名称')
    source_node = models.ForeignKey(FlowNode, null=True, blank=True, on_delete=models.SET_NULL, related_name="source_node", verbose_name='源节点')
    target_node = models.ForeignKey(FlowNode, null=True, blank=True, on_delete=models.SET_NULL, related_name="target_node", verbose_name='目标节点')
    ATTRIBUTE_TYPE_CHOICES = (
        (0, '同意'),
        (1, '拒绝'),
        (2, '其他'),
    )
    attribute_type = models.IntegerField(default=0,choices=ATTRIBUTE_TYPE_CHOICES, verbose_name='属性类型')
    
    class Meta:
        db_table = table_prefix + "flow_transition"
        verbose_name = "流程流转表"
        verbose_name_plural = verbose_name
        ordering = ("flow",)
class FlowTransitionLog(CoreModel,SoftDeleteModel):
    apply_form = models.ForeignKey(CellApplyForm,null=True, blank=True, related_name="transition_log", on_delete=models.CASCADE, db_constraint=False,
                            verbose_name="关联测试申请单", help_text="关联测试申请单")
    flow_node = models.ForeignKey(FlowNode,null=True, blank=True,  on_delete=models.CASCADE, db_constraint=False,
                            verbose_name="当前节点", help_text="当前节点")
    flow_transition_name = models.CharField(max_length=8, null=True, blank=True,verbose_name='流程流转名称',help_text='流程流转名称')
    handler =  models.CharField(max_length=32,null=True, blank=True, verbose_name="当前处理人", help_text="当前处理人")
    suggestion = models.TextField(null=True, blank=True, verbose_name="处理意见", help_text="处理意见")
    start_datetime = models.DateTimeField(null=True, blank=True, help_text="开始时间",verbose_name="开始时间")
    end_datetime = models.DateTimeField(null=True, blank=True, help_text="结束时间",verbose_name="结束时间")
    class Meta:
        db_table = table_prefix + "flow_transition_log"
        verbose_name = "测试申请单-工单流转记录表"
        verbose_name_plural = verbose_name
        ordering = ("-create_datetime",)

vue3页面

流程页面如下: image.png

流程节点配置如下: image.png

流程流转配置如下: image.png

申请单流程日志如下: image.png

结束

在最开始拿到这个需求的时候我是比较懵逼的,不知道从哪下手。后来把这个需求一步一步分解,一步一步去完成,自然而然就写完了。最后想说的是,拿到困难需求不要畏惧,能让你痛苦的就能让你成长,能让你技术能力快速提高!