工作流新建工单中

This commit is contained in:
caoqianming 2021-08-26 17:08:45 +08:00
parent 70b1305bb7
commit dbf4560423
3 changed files with 75 additions and 22 deletions

View File

@ -12,6 +12,7 @@ class Workflow(CommonAModel):
工作流
"""
name = models.CharField('名称', max_length=50)
sn_prefix = models.CharField('流水号前缀', max_length=50)
description = models.CharField('描述', max_length=200)
view_permission_check = models.BooleanField('查看权限校验', default=True, help_text='开启后,只允许工单的关联人(创建人、曾经的处理人)有权限查看工单')
limit_expression = models.JSONField('限制表达式', max_length=1000, default=dict, 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的用户提交工单)')
@ -49,6 +50,16 @@ class State(CommonAModel):
(PARTICIPANT_TYPE_FIELD, '工单的字段'),
(PARTICIPANT_TYPE_PARENT_FIELD, '父工单的字段')
)
STATE_DISTRIBUTE_TYPE_ACTIVE = 1 # 主动接单
STATE_DISTRIBUTE_TYPE_DIRECT = 2 # 直接处理(当前为多人的情况,都可以处理,而不需要先接单)
STATE_DISTRIBUTE_TYPE_RANDOM = 3 # 随机分配
STATE_DISTRIBUTE_TYPE_ALL = 4 # 全部处理
state_distribute_choices=(
(STATE_DISTRIBUTE_TYPE_ACTIVE, '主动接单'),
(STATE_DISTRIBUTE_TYPE_DIRECT, '直接处理'),
(STATE_DISTRIBUTE_TYPE_RANDOM, '随机分配'),
(STATE_DISTRIBUTE_TYPE_ALL, '全部处理'),
)
name = models.CharField('名称', max_length=50)
workflow = models.ForeignKey(Workflow, on_delete=models.CASCADE, verbose_name='所属工作流')
is_hidden = models.BooleanField('是否隐藏', default=False, help_text='设置为True时,获取工单步骤api中不显示此状态(当前处于此状态时除外)')
@ -56,8 +67,9 @@ class State(CommonAModel):
type = models.IntegerField('状态类型', default=0, choices=type_choices, help_text='0.普通类型 1.初始状态(用于新建工单时,获取对应的字段必填及transition信息) 2.结束状态(此状态下的工单不得再处理即没有对应的transition)')
enable_retreat = models.BooleanField('允许撤回', default=False, help_text='开启后允许工单创建人在此状态直接撤回工单到初始状态')
participant_type = models.IntegerField('参与者类型', choices=type2_choices, default=1, blank=True, help_text='0.无处理人,1.个人,2.多人,3.部门,4.角色,5.变量(支持工单创建人,创建人的leader),6.脚本,7.工单的字段内容(如表单中的"测试负责人",需要为用户名或者逗号隔开的多个用户名),8.父工单的字段内容。 初始状态请选择类型5参与人填create_by')
participant = models.CharField('参与者', default='', blank=True, max_length=1000, help_text='可以为空(无处理人的情况,如结束状态)、username\多个username(以,隔开)\部门id\角色id\变量(create_by,create_by_tl)\脚本记录的id等包含子工作流的需要设置处理人为loonrobot')
participant = models.JSONField('参与者', default=list, blank=True, help_text='可以为空(无处理人的情况,如结束状态)、userid、userid列表\部门id\角色id\变量(create_by,create_by_tl)\脚本记录的id等包含子工作流的需要设置处理人为loonrobot')
state_fields = models.JSONField('表单字段', default=dict, 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不显示, 字典的字典
distribute_type = models.IntegerField('分配方式', default=1, help_text='1.主动接单(如果当前处理人实际为多人的时候,需要先接单才能处理) 2.直接处理(即使当前处理人实际为多人,也可以直接处理) 3.随机分配(如果实际为多人,则系统会随机分配给其中一个人) 4.全部处理(要求所有参与人都要处理一遍,才能进入下一步)')
class Transition(CommonAModel):
"""
@ -115,15 +127,20 @@ class Ticket(CommonAModel):
"""
工单
"""
STATE_DISTRIBUTE_TYPE_ACTIVE = 1
STATE_DISTRIBUTE_TYPE_DIRECT = 2
STATE_DISTRIBUTE_TYPE_RANDOM = 3
STATE_DISTRIBUTE_TYPE_ALL = 4
TICKET_ACT_STATE_DRAFT = 0 # 草稿中
TICKET_ACT_STATE_ONGOING = 1 # 进行中
TICKET_ACT_STATE_BACK = 2 # 被退回
TICKET_ACT_STATE_RETREAT = 3 # 被撤回
TICKET_ACT_STATE_FINISH = 4 # 已完成
TICKET_ACT_STATE_CLOSED = 5 # 已关闭
act_state_choices =(
(STATE_DISTRIBUTE_TYPE_ACTIVE, '主动接单'),
(STATE_DISTRIBUTE_TYPE_DIRECT, '直接处理'),
(STATE_DISTRIBUTE_TYPE_RANDOM, '随机分配'),
(STATE_DISTRIBUTE_TYPE_ALL, '全部处理')
(TICKET_ACT_STATE_DRAFT, '草稿中'),
(TICKET_ACT_STATE_ONGOING, '进行中'),
(TICKET_ACT_STATE_BACK, '被退回'),
(TICKET_ACT_STATE_RETREAT, '被撤回'),
(TICKET_ACT_STATE_FINISH, '已完成'),
(TICKET_ACT_STATE_CLOSED, '已关闭')
)
title = models.CharField('标题', max_length=500, blank=True, default='', help_text="工单标题")
workflow = models.ForeignKey(Workflow, on_delete=models.CASCADE, verbose_name='关联工作流')
@ -135,8 +152,8 @@ class Ticket(CommonAModel):
in_add_node = models.BooleanField('加签状态中', default=False, help_text='是否处于加签状态下')
add_node_man = models.CharField('加签人', max_length=50, default='', blank=True, help_text='加签操作的人,工单当前处理人处理完成后会回到该处理人,当处于加签状态下才有效')
participant_type = models.IntegerField('当前处理人类型', default=0, help_text='0.无处理人,1.个人,2.多人,3.部门,4.角色', choices=State.type2_choices)
participant = models.JSONField('当前处理人', null=True, blank=True, help_text='可以为空(无处理人的情况,如结束状态)、userid、userid列表')
participant_type = models.IntegerField('当前处理人类型', default=0, help_text='0.无处理人,1.个人,2.多人', choices=State.type2_choices)
participant = models.JSONField('当前处理人', default=list, blank=True, help_text='可以为空(无处理人的情况,如结束状态)、userid、userid列表')
act_state = models.IntegerField('进行状态', default=1, help_text='当前工单的进行状态', choices=act_state_choices)
multi_all_person = models.JSONField('全部处理的结果', default=dict, blank=True, help_text='需要当前状态处理人全部处理时实际的处理结果json格式')

View File

@ -1,6 +1,9 @@
from apps.system.models import User
from apps.wf.models import CustomField, State, Ticket, Transition, Workflow
from rest_framework.exceptions import APIException
from django.utils import timezone
from datetime import timedelta
import random
class WfService(object):
@staticmethod
def get_worlflow_states(workflow:Workflow):
@ -72,16 +75,30 @@ class WfService(object):
return Transition.objects.filter(**kwargs).all()
@classmethod
def get_next_state_id_by_transition_and_ticket_info(cls, ticket:Ticket, transition: Transition, workflow:Workflow = None)->object:
def get_ticket_sn(cls, workflow:Workflow):
"""
生成工单流水号
"""
now = timezone.now()
today = str(now)[:10]+' 00:00:00'
next_day = str(now+timedelta(days=1))[:10]+' 00:00:00'
ticket_day_count_new = Ticket.objects.filter(create_time__gte=today, create_time__lte=next_day, workflow=workflow).count()+1
return '%s_%04d%02d%02d%04d' % (workflow.sn_prefix, now.year, now.month, now.day, ticket_day_count_new)
@classmethod
def get_next_state_id_by_transition_and_ticket_info(cls, ticket:Ticket, transition: Transition)->object:
"""
获取下个节点状态
"""
if ticket: # 如果是新建工单
source_state = ticket.state
else:
source_state = cls.get_workflow_start_state(workflow)
if transition.source_state != source_state:
raise APIException('流转错误')
# if ticket: # 如果是新建工单
# source_state = ticket.state
# else:
# source_state = cls.get_workflow_start_state(workflow)
# if transition.source_state != source_state:
# raise APIException('流转错误')
source_state = ticket.state
destination_state = transition.destination_state
if transition.condition_expression:
pass
@ -98,14 +115,15 @@ class WfService(object):
"""
return dict(destination_participant_type=State.PARTICIPANT_TYPE_PERSONAL,
destination_participant=ticket.create_by,
multi_all_person="{}")
multi_all_person=dict())
elif state.type == State.STATE_TYPE_END:
"""
到达结束状态
"""
return dict(destination_participant_type=State.PARTICIPANT_TYPE_PERSONAL,
destination_participant='',
multi_all_person="{}")
multi_all_person=dict())
multi_all_person_dict = {}
destination_participant_type, destination_participant = State.participant_type, State.participant
if destination_participant_type == State.PARTICIPANT_TYPE_FIELD:
@ -123,6 +141,14 @@ class WfService(object):
else:
destination_participant_type = State.PARTICIPANT_TYPE_PERSONAL
return dict(destination_participant_type)
if destination_participant_type == State.PARTICIPANT_TYPE_MULTI:
if state.distribute_type == State.STATE_DISTRIBUTE_TYPE_RANDOM:
destination_participant = random.choice(destination_participant)
elif state.distribute_type == State.STATE_DISTRIBUTE_TYPE_ALL:
for i in destination_participant:
multi_all_person_dict[i]={}
return dict(destination_participant_type=destination_participant_type,
destination_participant=destination_participant,
multi_all_person=multi_all_person_dict)

View File

@ -114,7 +114,17 @@ class TicketViewSet(OptimizationMixin, CreateUpdateCustomMixin, CreateModelMixin
if value == 2:
if key not in ticket_data or not ticket_data[key]:
raise APIException('字段{}必填'.format(key))
next_state = WfService.get_next_state_id_by_transition_and_ticket_info(ticket=None, transition=transition, workflow=serializer.data['workflow'])
ticket = serializer.save()
next_state = WfService.get_next_state_id_by_transition_and_ticket_info(ticket=ticket, transition=transition)
participant_info = WfService.get_ticket_state_participant_info(state=next_state, ticket=ticket, ticket_data=ticket.ticket_data)
destination_participant_type = participant_info.get('destination_participant_type', 0)
destination_participant = participant_info.get('destination_participant', '')
multi_all_person = participant_info.get('multi_all_person', '{}') # 多人需要全部处理情况
sn = WfService.get_ticket_sn(ticket.workflow)
if next_state.type == State.STATE_TYPE_END:
act_state = Ticket.TICKET_ACT_STATE_FINISH
elif next_state.type == State.STATE_TYPE_START:
pass
@action(methods=['get'], detail=True, perms_map={'get':'*'})
def flowsteps(self, request, pk=None):