增加workflow

This commit is contained in:
caoqianming 2021-08-16 17:25:40 +08:00
parent 015f3d5537
commit eda2c23659
15 changed files with 171 additions and 14 deletions

View File

@ -2,7 +2,7 @@
ENV = 'development'
# base api
VUE_APP_BASE_API = 'http://localhost:8000/api'
VUE_APP_BASE_API = 'http://47.95.0.242:2222/api'
# vue-cli uses the VUE_CLI_BABEL_TRANSPILE_MODULES environment variable,
# to control whether the babel-plugin-dynamic-import-node plugin is enabled.

View File

@ -1,6 +1,6 @@
from django.apps import AppConfig
class SystemConfig(AppConfig):
class EmConfig(AppConfig):
name = 'apps.em'
verbose_name = '设备仪器管理'

View File

@ -1,6 +1,6 @@
from django.apps import AppConfig
class SystemConfig(AppConfig):
class HrmConfig(AppConfig):
name = 'apps.hrm'
verbose_name = '人力资源管理'

View File

@ -30,23 +30,35 @@ class ServerInfoView(APIView):
return Response(ret)
class LogView(APIView):
def get(self, request, *args, **kwargs):
"""
查看最近的日志列表
:query name
"""
logs =[]
logs =[]
name = request.GET.get('name', None)
for root, dirs, files in os.walk(settings.LOG_PATH):
for file in files:
if len(logs)>50:break
filepath = os.path.join(root, file)
fsize = os.path.getsize(filepath)
if fsize:
logs.append({
"name":file,
"filepath":filepath,
"size":round(fsize/1000,1)
})
if name:
if filepath.contains(name):
fsize = os.path.getsize(filepath)
if fsize:
logs.append({
"name":file,
"filepath":filepath,
"size":round(fsize/1000,1)
})
else:
fsize = os.path.getsize(filepath)
if fsize:
logs.append({
"name":file,
"filepath":filepath,
"size":round(fsize/1000,1)
})
return Response(logs)
class LogDetailView(APIView):

View File

@ -1,6 +1,6 @@
from django.apps import AppConfig
class SystemConfig(AppConfig):
class PumConfig(AppConfig):
name = 'apps.pum'
verbose_name = '采购管理'

View File

@ -1,6 +1,6 @@
from django.apps import AppConfig
class SystemConfig(AppConfig):
class SamConfig(AppConfig):
name = 'apps.sam'
verbose_name = '销售管理'

View File

View File

@ -0,0 +1,3 @@
from django.contrib import admin
# Register your models here.

View File

@ -0,0 +1,7 @@
from django.apps import AppConfig
class WfConfig(AppConfig):
name = 'apps.wf'
verbose_name = '工作流管理'

View File

@ -0,0 +1,88 @@
from django.db import models
from django.db.models.base import Model
import django.utils.timezone as timezone
from django.db.models.query import QuerySet
from apps.system.models import CommonAModel, CommonBModel, Organization, User, Dict, File
from utils.model import SoftModel, BaseModel
from simple_history.models import HistoricalRecords
class Workflow(CommonAModel):
"""
工作流
"""
name = models.CharField('名称', max_length=50)
description = models.CharField('描述', max_length=200)
view_permission_check = models.BooleanField('查看权限校验', default=True, help_text='开启后,只允许工单的关联人(创建人、曾经的处理人)有权限查看工单')
title_template = models.CharField('标题模板', max_length=50, default='你有一个待办工单:{title}', null=True, blank=True, help_text='工单字段的值可以作为参数写到模板中,格式如:你有一个待办工单:{title}')
class State(BaseModel):
"""
状态记录
"""
type_choices = (
(0, '普通类型'),
(1, '初始状态'),
(2, '结束状态')
)
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中不显示此状态(当前处于此状态时除外)')
sort = models.IntegerField('状态顺序', default=0, help_text='用于工单步骤接口时step上状态的顺序(因为存在网状情况,所以需要人为设定顺序),值越小越靠前')
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('参与者类型', default=1, blank=True, help_text='0.无处理人,1.个人,2.多人,3.部门,4.角色,5.变量(支持工单创建人,创建人的leader),6.脚本,7.工单的字段内容(如表单中的"测试负责人",需要为用户名或者逗号隔开的多个用户名),8.父工单的字段内容。 初始状态请选择类型5参与人填creator')
class Transition(BaseModel):
"""
工作流流转定时器条件(允许跳过) 条件流转与定时器不可同时存在
"""
attribute_type_choices = (
(1, '同意'),
(2, '拒绝'),
(3, '其他')
)
name = models.CharField('操作', max_length=50)
workflow = models.ForeignKey(Workflow, on_delete=models.CASCADE, verbose_name='所属工作流')
timer = models.IntegerField('定时器(单位秒)', default=0, help_text='单位秒。处于源状态X秒后如果状态都没有过变化则自动流转到目标状态。设置时间有效')
source_state = models.ForeignKey(State, on_delete=models.CASCADE, verbose_name='源状态', related_name='sstate_transition')
destination_state = models.ForeignKey(State, on_delete=models.CASCADE, verbose_name='目的状态', related_name='dstate_transition')
condition_expression = models.JSONField('条件表达式', max_length=1000, default='[]', help_text='流转条件表达式,根据表达式中的条件来确定流转的下个状态,格式为[{"expression":"{days} > 3 and {days}<10", "target_state":11}] 其中{}用于填充工单的字段key,运算时会换算成实际的值当符合条件下个状态将变为target_state_id中的值,表达式只支持简单的运算或datetime/time运算.loonflow会以首次匹配成功的条件为准所以多个条件不要有冲突' )
attribute_type = models.IntegerField('属性类型', default=1, choices=attribute_type_choices, help_text='属性类型1.同意2.拒绝3.其他')
field_require_check = models.BooleanField('是否校验必填项', default=True, help_text='默认在用户点击操作的时候需要校验工单表单的必填项,如果设置为否则不检查。用于如"退回"属性的操作,不需要填写表单内容')
class CustomField(BaseModel):
"""自定义字段, 设定某个工作流有哪些自定义字段"""
field_type_choices = (
('string', '字符串'),
('int', '整型'),
('float', '浮点'),
('bol', '布尔'),
('date', '日期'),
('datetime', '日期时间'),
('radio', '单选'),
('checkbox', '多选'),
('select', '单选下拉'),
('mutiselect', '多选下拉'),
('textarea', '文本域'),
('selectuser', '单选用户'),
('selectusers', '多选用户'),
('file', '附件')
)
workflow = models.ForeignKey(Workflow, on_delete=models.CASCADE, verbose_name='所属工作流')
field_type = models.IntegerField('类型', help_text='5.字符串10.整形15.浮点型20.布尔25.日期30.日期时间35.单选框40.多选框45.下拉列表50.多选下拉列表55.文本域60.用户名, 70.多选的用户名, 80.附件(只保存路径,多个使用逗号隔开)')
field_key = models.CharField('字段标识', max_length=50, help_text='字段类型请尽量特殊,避免与系统中关键字冲突')
field_name = models.CharField('字段名称', max_length=50)
sort = models.IntegerField('排序', default=0, help_text='工单基础字段在表单中排序为:流水号0,标题20,状态id40,状态名41,创建人80,创建时间100,更新时间120.前端展示工单信息的表单可以根据这个id顺序排列')
default_value = models.CharField('默认值', null=True, blank=True, max_length=100, help_text='前端展示时,可以将此内容作为表单中的该字段的默认值')
description = models.CharField('描述', max_length=100, blank=True, default='', help_text='字段的描述信息,可用于显示在字段的下方对该字段的详细描述')
placeholder = models.CharField('占位符', max_length=100, blank=True, default='', help_text='用户工单详情表单中作为字段的占位符显示')
field_template = models.TextField('文本域模板', default='', blank=True, help_text='文本域类型字段前端显示时可以将此内容作为字段的placeholder')
boolean_field_display = models.JSONField('布尔类型显示名', default='{}', blank=True,
help_text='当为布尔类型时候,可以支持自定义显示形式。{"1":"","0":""}或{"1":"需要","0":"不需要"},注意数字也需要引号')
field_choice = models.JSONField('radio、checkbox、select的选项', default='{}', blank=True,
help_text='radio,checkbox,select,multiselect类型可供选择的选项格式为json如:{"1":"中国", "2":"美国"},注意数字也需要引号')
label = models.JSONField('标签', blank=True, default='{}', help_text='自定义标签json格式调用方可根据标签自行处理特殊场景逻辑loonflow只保存文本内容')

View File

@ -0,0 +1,9 @@
from rest_framework.serializers import ModelSerializer
from .models import Workflow
class WorkflowSerializer(ModelSerializer):
class Meta:
model = Workflow
fields = '__all__'

View File

@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

12
hb_server/apps/wf/urls.py Normal file
View File

@ -0,0 +1,12 @@
from django.db.models import base
from rest_framework import urlpatterns
from apps.pum.views import VendorViewSet
from django.urls import path, include
from rest_framework.routers import DefaultRouter
router = DefaultRouter()
router.register('vendor', VendorViewSet, basename='vendor')
urlpatterns = [
path('', include(router.urls)),
]

View File

@ -0,0 +1,18 @@
from apps.wf.serializers import WorkflowSerializer
from django.shortcuts import render
from rest_framework.viewsets import ModelViewSet
from apps.wf.models import Workflow, State, Transition
from apps.system.mixins import CreateUpdateModelAMixin, OptimizationMixin
# Create your views here.
class WorkflowViewSet(CreateUpdateModelAMixin, ModelViewSet):
perms_map = {'get': '*', 'post': 'workflow_create',
'put': 'workflow_update', 'delete': 'workflow_delete'}
queryset = Workflow.objects.all()
serializer_class = WorkflowSerializer
search_fields = ['name', 'description']
filterset_fields = []
ordering_fields = ['create_time']
ordering = ['-create_time']

View File

@ -197,6 +197,11 @@ CELERYD_MAX_TASKS_PER_CHILD = 100 # 每个worker最多执行300个任务就会
CELERY_TIMEZONE = 'Asia/Shanghai' # 设置时区
CELERY_ENABLE_UTC = True # 启动时区设置
# swagger配置
SWAGGER_SETTINGS = {
'LOGIN_URL':'/api/admin/login/',
'LOGOUT_URL':'/api/admin/logout/'
}
# 日志配置
# 创建日志的路径