models.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. import os
  2. import uuid
  3. from django.db import models
  4. from apps.loon_base_model import BaseModel
  5. class Workflow(BaseModel):
  6. """
  7. 工作流
  8. """
  9. name = models.CharField('名称', max_length=50)
  10. description = models.CharField('描述', max_length=50)
  11. flowchart = models.FileField('流程图', upload_to='flowchart', blank=True, help_text='工作流的流程图,为了方便别人')
  12. notices = models.CharField('通知', default='', blank=True, max_length=50, help_text='CustomNotice中的id.逗号隔开多个通知方式')
  13. view_permission_check = models.BooleanField('查看权限校验', default=True, help_text='开启后,只允许工单的关联人(创建人、曾经的处理人)有权限查看工单')
  14. limit_expression = models.CharField('限制表达式', max_length=1000, default='{}', blank=True, help_text='限制周期({"period":24} 24小时), 限制次数({"count":1}在限制周期内只允许提交1次), 限制级别({"level":1} 针对(1单个用户 2全局)限制周期限制次数,默认特定用户);允许特定人员提交({"allow_persons":"zhangsan,lisi"}只允许张三提交工单,{"allow_depts":"1,2"}只允许部门id为1和2的用户提交工单,{"allow_roles":"1,2"}只允许角色id为1和2的用户提交工单)')
  15. display_form_str = models.CharField('展现表单字段', max_length=10000, default='[]', blank=True, help_text='默认"[]",用于用户只有对应工单查看权限时显示哪些字段,field_key的list的json,如["days","sn"],内置特殊字段participant_info.participant_name:当前处理人信息(部门名称、角色名称),state.state_name:当前状态的状态名,workflow.workflow_name:工作流名称')
  16. # default_notice_to = models.CharField('默认通知人', max_length=50, default='', blank=True, help_text='表单创建及结束时会发送相应通知信息')
  17. class Meta:
  18. verbose_name = '工作流'
  19. verbose_name_plural = '工作流'
  20. class State(BaseModel):
  21. """
  22. 状态记录, 变量支持通过脚本获取
  23. """
  24. name = models.CharField('名称', max_length=50)
  25. workflow_id = models.IntegerField('工作流')
  26. sub_workflow_id = models.IntegerField('子工作流id', default=0, blank=True, help_text='如果需要在此状态启用子工单,请填写对应的工作流id')
  27. is_hidden = models.BooleanField('是否隐藏', default=False, help_text='设置为True时,获取工单步骤api中不显示此状态(当前处于此状态时除外)')
  28. order_id = models.IntegerField('状态顺序', default=0, help_text='用于工单步骤接口时,step上状态的顺序(因为存在网状情况,所以需要人为设定顺序),值越小越靠前')
  29. type_id = models.IntegerField('状态类型id', default=0, help_text='0.普通类型 1.初始状态(用于新建工单时,获取对应的字段必填及transition信息) 2.结束状态(此状态下的工单不得再处理,即没有对应的transition)')
  30. remember_last_man_enable = models.BooleanField('记忆最后处理人', default=False, help_text='开启后,到达此状态时会先检查之前是否有人在此状态处理过,如果有则处理人为最后一次处理的人')
  31. participant_type_id = models.IntegerField('参与者类型id', default=1, blank=True, help_text='0.无处理人,1.个人,2.多人,3.部门,4.角色,5.变量(支持工单创建人,创建人的leader),6.脚本,7.工单的字段内容(如表单中的"测试负责人",需要为用户名或者逗号隔开的多个用户名),8.父工单的字段内容。 初始状态请选择类型5,参与人填creator')
  32. participant = models.CharField('参与者', default='', blank=True, max_length=100, help_text='可以为空(无处理人的情况,如结束状态)、username\多个username(以,隔开)\部门id\角色id\变量(creator,creator_tl)\脚本记录的id等,包含子工作流的需要设置处理人为loonrobot')
  33. distribute_type_id = models.IntegerField('分配方式', default=1, help_text='1.主动接单(如果当前处理人实际为多人的时候,需要先接单才能处理) 2.直接处理(即使当前处理人实际为多人,也可以直接处理) 3.随机分配(如果实际为多人,则系统会随机分配给其中一个人) 4.全部处理(要求所有参与人都要处理一遍,才能进入下一步)')
  34. state_field_str = models.TextField('表单字段', default='{}', help_text='json格式字典存储,包括读写属性1:只读,2:必填,3:可选. 示例:{"created_at":1,"title":2, "sn":1}, 内置特殊字段participant_info.participant_name:当前处理人信息(部门名称、角色名称),state.state_name:当前状态的状态名,workflow.workflow_name:工作流名称') # json格式存储,包括读写属性1:只读,2:必填,3:可选,4:不显示, 字典的字典
  35. label = models.CharField('状态标签', max_length=1000, default='{}', help_text='json格式,由调用方根据实际定制需求自行确定,如状态下需要显示哪些前端组件:{"components":[{"AppList":1, "ProjectList":7}]}')
  36. class Meta:
  37. verbose_name = '工作流状态'
  38. verbose_name_plural = '工作流状态'
  39. class Transition(BaseModel):
  40. """
  41. 工作流流转,定时器,条件(允许跳过), 条件流转与定时器不可同时存在
  42. """
  43. name = models.CharField('操作', max_length=50)
  44. workflow_id = models.IntegerField('工作流id')
  45. transition_type_id = models.IntegerField('流转类型', default=1, help_text='1.常规流转,2.定时器流转,需要设置定时器时间')
  46. timer = models.IntegerField('定时器(单位秒)', default=0, help_text='流转类型设置为定时器流转时生效,单位秒。处于源状态X秒后如果状态都没有过变化则自动流转到目标状态')
  47. source_state_id = models.IntegerField('源状态id')
  48. destination_state_id = models.IntegerField('目的状态id')
  49. condition_expression = models.CharField('条件表达式', max_length=1000, default='[]', help_text='流转条件表达式,根据表达式中的条件来确定流转的下个状态,格式为[{"expression":"{days} > 3 and {days}<10", "target_state_id":11}] 其中{}用于填充工单的字段key,运算时会换算成实际的值,当符合条件下个状态将变为target_state_id中的值,表达式只支持简单的运算或datetime/time运算.loonflow会以首次匹配成功的条件为准,所以多个条件不要有冲突' )
  50. attribute_type_id = models.IntegerField('属性类型', default=1, help_text='属性类型,1.同意,2.拒绝,3.其他')
  51. field_require_check = models.BooleanField('是否校验必填项', default=True, help_text='默认在用户点击操作的时候需要校验工单表单的必填项,如果设置为否则不检查。用于如"退回"属性的操作,不需要填写表单内容')
  52. alert_enable = models.BooleanField('点击弹窗提示', default=False)
  53. alert_text = models.CharField('弹窗内容', max_length=100, default='', blank=True)
  54. class Meta:
  55. verbose_name = '工作流流转'
  56. verbose_name_plural = '工作流流转'
  57. class CustomField(BaseModel):
  58. """自定义字段, 设定某个工作流有哪些自定义字段"""
  59. workflow_id = models.IntegerField('工作流id')
  60. field_type_id = models.IntegerField('类型', help_text='5.字符串,10.整形,15.浮点型,20.布尔,25.日期,30.日期时间,35.单选框,40.多选框,45.下拉列表,50.多选下拉列表,55.文本域,60.用户名, 70.多选的用户名, 80.附件(只保存路径,多个使用逗号隔开)')
  61. field_key = models.CharField('字段标识', max_length=50, help_text='字段类型请尽量特殊,避免与系统中关键字冲突')
  62. field_name = models.CharField('字段名称', max_length=50)
  63. order_id = models.IntegerField('排序', default=0, help_text='工单基础字段在表单中排序为:流水号0,标题20,状态id40,状态名41,创建人80,创建时间100,更新时间120.前端展示工单信息的表单可以根据这个id顺序排列')
  64. default_value = models.CharField('默认值', null=True, blank=True, max_length=100, help_text='前端展示时,可以将此内容作为表单中的该字段的默认值')
  65. description = models.CharField('描述', max_length=100, blank=True, default='', help_text='字段的描述信息,对于非文本域字段可以将此内容作为placeholder')
  66. field_template = models.TextField('文本域模板', default='', blank=True, help_text='文本域类型字段前端显示时可以将此内容作为字段的placeholder')
  67. boolean_field_display = models.CharField('布尔类型显示名', max_length=100, default='{}', blank=True,
  68. help_text='当为布尔类型时候,可以支持自定义显示形式。{"1":"是","0":"否"}或{"1":"需要","0":"不需要"},注意数字也需要引号')
  69. field_choice = models.CharField('radio、checkbox、select的选项', max_length=1000, default='{}', blank=True,
  70. help_text='radio,checkbox,select,multiselect类型可供选择的选项,格式为json如:{"1":"中国", "2":"美国"},注意数字也需要引号')
  71. label = models.CharField('标签', max_length=100, blank=True, default='{}', help_text='自定义标签,json格式,调用方可根据标签自行处理特殊场景逻辑,loonflow只保存文本内容')
  72. class Meta:
  73. verbose_name = '工作流自定义字段'
  74. verbose_name_plural = '工作流自定义字段'
  75. def upload_workflow_script(instance, filename):
  76. """
  77. 因为脚本中可能会存在一些私密信息,如账号密码等,所以重命名文件,避免可以直接下载此文件
  78. :param instance:
  79. :param filename:
  80. :return:
  81. """
  82. upload_to = 'workflow_script'
  83. ext = filename.split('.')[-1]
  84. if ext != 'py':
  85. raise Exception('只支持python脚本')
  86. filename = '{}.{}'.format(uuid.uuid1(), ext)
  87. return os.path.join(upload_to, filename)
  88. class WorkflowScript(BaseModel):
  89. """
  90. 流程中执行的脚本
  91. """
  92. name = models.CharField('名称', max_length=50)
  93. saved_name = models.FileField('存储的文件名', upload_to=upload_workflow_script, help_text='请上传python脚本,media/workflow_script/demo_script.py为示例脚本,请参考编写')
  94. description = models.CharField('描述', max_length=100, null=True, blank=True)
  95. is_active = models.BooleanField('可用', default=True, help_text='此处可用时,才允许实际执行')
  96. class Meta:
  97. verbose_name = '工作流脚本'
  98. verbose_name_plural = '工作流脚本'
  99. def upload_notice_script(instance, filename):
  100. """
  101. 因为通知脚本中可能会存在一些私密信息,如账号密码等,所以重命名文件,避免可以直接下载此文件
  102. :param instance:
  103. :param filename:
  104. :return:
  105. """
  106. upload_to = 'notice_script'
  107. ext = filename.split('.')[-1]
  108. if ext != 'py':
  109. raise Exception('只支持python脚本')
  110. filename = '{}.{}'.format(uuid.uuid1(), ext)
  111. return os.path.join(upload_to, filename)
  112. class CustomNotice(BaseModel):
  113. """
  114. 自定义通知方式
  115. """
  116. name = models.CharField('名称', max_length=50)
  117. description = models.CharField('描述', max_length=100, null=True, blank=True)
  118. script = models.FileField('通知脚本', upload_to=upload_notice_script, null=True, blank=True)
  119. title_template = models.CharField('标题模板', max_length=50, default='你有一个待办工单:{title}', null=True, blank=True, help_text='工单字段的值可以作为参数写到模板中,格式如:你有一个待办工单:{title}')
  120. content_template = models.CharField('内容模板', max_length=1000, default='标题:{title}, 创建时间:{gmt_created}', null=True, blank=True, help_text='工单字段的值可以作为参数写到模板中,格式如:标题:{title}, 创建时间:{gmt_created}')
  121. class Meta:
  122. verbose_name = '自定义通知脚本'
  123. verbose_name_plural = '自定义通知脚本'