This commit is contained in:
commit
a18cabf86d
|
@ -218,6 +218,16 @@ export const asyncRoutes = [
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: 'docs-link2',
|
||||||
|
component: Layout,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: process.env.VUE_APP_BASE_API + '/swagger/',
|
||||||
|
meta: { title: 'Swagger文档', icon: 'link', perms: ['dev_docs'] }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: 'admin-link',
|
path: 'admin-link',
|
||||||
component: Layout,
|
component: Layout,
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
from django.apps import AppConfig
|
from django.apps import AppConfig
|
||||||
|
|
||||||
class SystemConfig(AppConfig):
|
class EmConfig(AppConfig):
|
||||||
name = 'apps.em'
|
name = 'apps.em'
|
||||||
verbose_name = '设备仪器管理'
|
verbose_name = '设备仪器管理'
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
# Generated by Django 3.2.6 on 2021-08-16 01:14
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('em', '0001_initial'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='equipment',
|
||||||
|
name='model',
|
||||||
|
field=models.CharField(blank=True, max_length=60, null=True, verbose_name='规格型号'),
|
||||||
|
),
|
||||||
|
]
|
|
@ -35,5 +35,5 @@ class Equipment(CommonBModel):
|
||||||
verbose_name_plural = verbose_name
|
verbose_name_plural = verbose_name
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.name + '-' + self.name
|
return self.number + '-' + self.name
|
||||||
|
|
|
@ -3,11 +3,11 @@ from rest_framework.viewsets import ModelViewSet
|
||||||
|
|
||||||
from apps.em.models import Equipment
|
from apps.em.models import Equipment
|
||||||
from apps.em.serializers import EquipmentSerializer
|
from apps.em.serializers import EquipmentSerializer
|
||||||
from apps.system.mixins import OptimizationMixin
|
from apps.system.mixins import CreateUpdateModelAMixin, OptimizationMixin
|
||||||
|
|
||||||
|
|
||||||
# Create your views here.
|
# Create your views here.
|
||||||
class EquipmentViewSet(ModelViewSet):
|
class EquipmentViewSet(CreateUpdateModelAMixin, OptimizationMixin, ModelViewSet):
|
||||||
"""
|
"""
|
||||||
设备台账-增删改查
|
设备台账-增删改查
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
from django.apps import AppConfig
|
from django.apps import AppConfig
|
||||||
|
|
||||||
class SystemConfig(AppConfig):
|
class HrmConfig(AppConfig):
|
||||||
name = 'apps.sam'
|
name = 'apps.hrm'
|
||||||
verbose_name = '人力资源管理'
|
verbose_name = '人力资源管理'
|
||||||
|
|
||||||
|
def ready(self):
|
||||||
|
import apps.hrm.signals
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
# Generated by Django 3.2.6 on 2021-08-13 09:16
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
import django.utils.timezone
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
initial = True
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Employee',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('create_time', models.DateTimeField(default=django.utils.timezone.now, help_text='创建时间', verbose_name='创建时间')),
|
||||||
|
('update_time', models.DateTimeField(auto_now=True, help_text='修改时间', verbose_name='修改时间')),
|
||||||
|
('is_deleted', models.BooleanField(default=False, help_text='删除标记', verbose_name='删除标记')),
|
||||||
|
('number', models.CharField(blank=True, max_length=50, null=True, unique=True, verbose_name='人员编号')),
|
||||||
|
('photo', models.CharField(blank=True, max_length=1000, null=True, verbose_name='证件照')),
|
||||||
|
('ID_number', models.CharField(blank=True, max_length=100, null=True, verbose_name='身份证号')),
|
||||||
|
('gender', models.CharField(default='男', max_length=10, verbose_name='性别')),
|
||||||
|
('signature', models.CharField(blank=True, max_length=200, null=True, verbose_name='签名图片')),
|
||||||
|
('create_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='employee_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人')),
|
||||||
|
('update_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='employee_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')),
|
||||||
|
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='employee_user', to=settings.AUTH_USER_MODEL)),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': '员工补充信息',
|
||||||
|
'verbose_name_plural': '员工补充信息',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
|
@ -9,23 +9,18 @@ from simple_history.models import HistoricalRecords
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Employee(BaseModel):
|
class Employee(CommonAModel):
|
||||||
"""
|
"""
|
||||||
员工信息
|
员工信息
|
||||||
"""
|
"""
|
||||||
job_choices = (
|
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='employee_user')
|
||||||
('在职', '在职'),
|
|
||||||
('离职', '离职'),
|
|
||||||
)
|
|
||||||
name = models.CharField('姓名', max_length=50)
|
|
||||||
number = models.CharField('人员编号', max_length=50,null=True, blank=True, unique=True)
|
number = models.CharField('人员编号', max_length=50,null=True, blank=True, unique=True)
|
||||||
gender = models.CharField('性别', max_length=10,null=True, blank=True)
|
photo = models.CharField('证件照', max_length=1000, null=True, blank=True)
|
||||||
phone = models.CharField('手机号', max_length=11,null=True, blank=True, unique=True)
|
ID_number = models.CharField('身份证号', max_length=100, null=True, blank=True)
|
||||||
jobstate = models.CharField('在职状态', max_length=11,choices=job_choices, default='在职')
|
gender = models.CharField('性别', max_length=10, default='男')
|
||||||
dept = models.ForeignKey(Organization, verbose_name='关联部门', on_delete=models.CASCADE, related_name='employee_dept')
|
signature = models.CharField('签名图片', max_length=200, null=True, blank=True)
|
||||||
description = models.CharField('描述', max_length=200, blank=True, null=True)
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = '客户信息'
|
verbose_name = '员工补充信息'
|
||||||
verbose_name_plural = verbose_name
|
verbose_name_plural = verbose_name
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
from apps.system.models import User
|
||||||
|
from rest_framework.serializers import ModelSerializer
|
||||||
|
|
||||||
|
from .models import Employee
|
||||||
|
from apps.system.serializers import UserListSerializer, UserSimpleSerializer
|
||||||
|
from django.db.models.query import Prefetch
|
||||||
|
|
||||||
|
class EmployeeSerializer(ModelSerializer):
|
||||||
|
# user_ = UserListSerializer(source='user', read_only=True)
|
||||||
|
class Meta:
|
||||||
|
model = Employee
|
||||||
|
fields = '__all__'
|
||||||
|
# @staticmethod
|
||||||
|
# def setup_eager_loading(queryset):
|
||||||
|
# """ Perform necessary eager loading of data. """
|
||||||
|
# queryset = queryset.select_related('user', 'user__dept')
|
||||||
|
# # queryset = queryset.prefetch_related('user','user__dept')
|
||||||
|
# queryset = queryset.prefetch_related(
|
||||||
|
# Prefetch('user_',
|
||||||
|
# queryset=User.objects.filter(employee_user__isnull=True))
|
||||||
|
# )
|
||||||
|
# return queryset
|
|
@ -0,0 +1,9 @@
|
||||||
|
from django.db.models.signals import post_save
|
||||||
|
from apps.system.models import User
|
||||||
|
from django.dispatch import receiver
|
||||||
|
from apps.hrm.models import Employee
|
||||||
|
|
||||||
|
@receiver(post_save, sender=User)
|
||||||
|
def createEmployee(sender, instance, created, **kwargs):
|
||||||
|
if created:
|
||||||
|
Employee.objects.get_or_create(user=instance)
|
|
@ -0,0 +1,12 @@
|
||||||
|
from django.db.models import base
|
||||||
|
from rest_framework import urlpatterns
|
||||||
|
from apps.hrm.views import EmployeeViewSet
|
||||||
|
from django.urls import path, include
|
||||||
|
from rest_framework.routers import DefaultRouter
|
||||||
|
|
||||||
|
router = DefaultRouter()
|
||||||
|
router.register('employee', EmployeeViewSet, basename='employee')
|
||||||
|
urlpatterns = [
|
||||||
|
path('', include(router.urls)),
|
||||||
|
]
|
||||||
|
|
|
@ -1,3 +1,15 @@
|
||||||
from django.shortcuts import render
|
from django.shortcuts import render
|
||||||
|
from rest_framework.viewsets import ModelViewSet, GenericViewSet
|
||||||
|
from rest_framework.mixins import UpdateModelMixin, RetrieveModelMixin
|
||||||
|
from apps.system.mixins import CreateUpdateModelAMixin, OptimizationMixin
|
||||||
|
from apps.hrm.models import Employee
|
||||||
|
from apps.hrm.serializers import EmployeeSerializer
|
||||||
# Create your views here.
|
# Create your views here.
|
||||||
|
class EmployeeViewSet(CreateUpdateModelAMixin, OptimizationMixin, UpdateModelMixin, RetrieveModelMixin, GenericViewSet):
|
||||||
|
"""
|
||||||
|
员工详细信息
|
||||||
|
"""
|
||||||
|
perms_map = {'get': '*', 'put': 'employee_update'}
|
||||||
|
queryset = Employee.objects.all()
|
||||||
|
serializer_class = EmployeeSerializer
|
||||||
|
ordering = ['-pk']
|
|
@ -1,5 +1,6 @@
|
||||||
from django.shortcuts import render
|
from django.shortcuts import render
|
||||||
import psutil
|
import psutil
|
||||||
|
from rest_framework import response
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
from rest_framework.views import APIView
|
from rest_framework.views import APIView
|
||||||
from rest_framework.permissions import IsAuthenticated
|
from rest_framework.permissions import IsAuthenticated
|
||||||
|
@ -7,6 +8,8 @@ from rest_framework.viewsets import ViewSet
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
import os
|
import os
|
||||||
from rest_framework import serializers, status
|
from rest_framework import serializers, status
|
||||||
|
from drf_yasg import openapi
|
||||||
|
from drf_yasg.utils import swagger_auto_schema
|
||||||
# Create your views here.
|
# Create your views here.
|
||||||
|
|
||||||
class ServerInfoView(APIView):
|
class ServerInfoView(APIView):
|
||||||
|
@ -29,26 +32,55 @@ class ServerInfoView(APIView):
|
||||||
ret['disk']['percent'] = disk.percent
|
ret['disk']['percent'] = disk.percent
|
||||||
return Response(ret)
|
return Response(ret)
|
||||||
|
|
||||||
|
def get_file_list(file_path):
|
||||||
|
dir_list = os.listdir(file_path)
|
||||||
|
if not dir_list:
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
# 注意,这里使用lambda表达式,将文件按照最后修改时间顺序升序排列
|
||||||
|
# os.path.getmtime() 函数是获取文件最后修改时间
|
||||||
|
# os.path.getctime() 函数是获取文件最后创建时间
|
||||||
|
dir_list = sorted(dir_list,key=lambda x: os.path.getmtime(os.path.join(file_path, x)), reverse=True)
|
||||||
|
# print(dir_list)
|
||||||
|
return dir_list
|
||||||
|
|
||||||
class LogView(APIView):
|
class LogView(APIView):
|
||||||
|
|
||||||
|
@swagger_auto_schema(manual_parameters=[
|
||||||
|
openapi.Parameter('name', openapi.IN_QUERY, description='日志文件名', type=openapi.TYPE_STRING)
|
||||||
|
])
|
||||||
def get(self, request, *args, **kwargs):
|
def get(self, request, *args, **kwargs):
|
||||||
"""
|
"""
|
||||||
查看最近的日志列表
|
查看最近的日志列表
|
||||||
|
:query name
|
||||||
"""
|
"""
|
||||||
logs =[]
|
logs =[]
|
||||||
for root, dirs, files in os.walk(settings.LOG_PATH):
|
name = request.GET.get('name', None)
|
||||||
for file in files:
|
# for root, dirs, files in os.walk(settings.LOG_PATH):
|
||||||
if len(logs)>50:break
|
# files.reverse()
|
||||||
filepath = os.path.join(root, file)
|
for file in get_file_list(settings.LOG_PATH):
|
||||||
|
if len(logs)>50:break
|
||||||
|
filepath = os.path.join(settings.LOG_PATH, file)
|
||||||
|
if name:
|
||||||
|
if name in filepath:
|
||||||
|
fsize = os.path.getsize(filepath)
|
||||||
|
if fsize:
|
||||||
|
logs.append({
|
||||||
|
"name":file,
|
||||||
|
"filepath":filepath,
|
||||||
|
"size":round(fsize/1000,1)
|
||||||
|
})
|
||||||
|
else:
|
||||||
fsize = os.path.getsize(filepath)
|
fsize = os.path.getsize(filepath)
|
||||||
if fsize:
|
if fsize:
|
||||||
logs.append({
|
logs.append({
|
||||||
"name":file,
|
"name":file,
|
||||||
"filepath":filepath,
|
"filepath":filepath,
|
||||||
"size":round(fsize/1000,1)
|
"size":round(fsize/1000,1)
|
||||||
})
|
})
|
||||||
return Response(logs)
|
return Response(logs)
|
||||||
|
|
||||||
|
|
||||||
class LogDetailView(APIView):
|
class LogDetailView(APIView):
|
||||||
|
|
||||||
def get(self, request, name):
|
def get(self, request, name):
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
from django.apps import AppConfig
|
from django.apps import AppConfig
|
||||||
|
|
||||||
class SystemConfig(AppConfig):
|
class PumConfig(AppConfig):
|
||||||
name = 'apps.pum'
|
name = 'apps.pum'
|
||||||
verbose_name = '采购管理'
|
verbose_name = '采购管理'
|
||||||
|
|
||||||
|
|
|
@ -3,11 +3,11 @@ from rest_framework.viewsets import ModelViewSet
|
||||||
|
|
||||||
from apps.pum.models import Vendor
|
from apps.pum.models import Vendor
|
||||||
from apps.pum.serializers import VendorSerializer
|
from apps.pum.serializers import VendorSerializer
|
||||||
from apps.system.mixins import OptimizationMixin
|
from apps.system.mixins import CreateUpdateModelAMixin, OptimizationMixin
|
||||||
|
|
||||||
|
|
||||||
# Create your views here.
|
# Create your views here.
|
||||||
class VendorViewSet(ModelViewSet):
|
class VendorViewSet(CreateUpdateModelAMixin, ModelViewSet):
|
||||||
"""
|
"""
|
||||||
供应商-增删改查
|
供应商-增删改查
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
from django.apps import AppConfig
|
from django.apps import AppConfig
|
||||||
|
|
||||||
class SystemConfig(AppConfig):
|
class SamConfig(AppConfig):
|
||||||
name = 'apps.sam'
|
name = 'apps.sam'
|
||||||
verbose_name = '销售管理'
|
verbose_name = '销售管理'
|
||||||
|
|
||||||
|
|
|
@ -119,7 +119,14 @@ class UserSimpleSerializer(serializers.ModelSerializer):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = User
|
model = User
|
||||||
fields = ['id', 'username', 'name']
|
fields = ['id', 'username', 'name']
|
||||||
|
|
||||||
|
# class UserStandardSerializer(serializers.ModelSerializer):
|
||||||
|
# dept_name = serializers.StringRelatedField(source='dept')
|
||||||
|
# class Meta:
|
||||||
|
# model = User
|
||||||
|
# fields = ['id', 'username', 'name', 'is_active', 'dept_name', 'dept']
|
||||||
|
|
||||||
|
|
||||||
class UserListSerializer(serializers.ModelSerializer):
|
class UserListSerializer(serializers.ModelSerializer):
|
||||||
"""
|
"""
|
||||||
用户列表序列化
|
用户列表序列化
|
||||||
|
@ -137,6 +144,11 @@ class UserListSerializer(serializers.ModelSerializer):
|
||||||
queryset = queryset.select_related('superior','dept')
|
queryset = queryset.select_related('superior','dept')
|
||||||
queryset = queryset.prefetch_related('roles',)
|
queryset = queryset.prefetch_related('roles',)
|
||||||
return queryset
|
return queryset
|
||||||
|
|
||||||
|
def get_field_names(self, declared_fields, info):
|
||||||
|
if hasattr(self.Meta.model, 'employee_user'):
|
||||||
|
self.Meta.fields.append('employee_user')
|
||||||
|
return super().get_field_names(declared_fields, info)
|
||||||
|
|
||||||
class UserModifySerializer(serializers.ModelSerializer):
|
class UserModifySerializer(serializers.ModelSerializer):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
from django.contrib import admin
|
||||||
|
|
||||||
|
# Register your models here.
|
|
@ -0,0 +1,7 @@
|
||||||
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
class WfConfig(AppConfig):
|
||||||
|
name = 'apps.wf'
|
||||||
|
verbose_name = '工作流管理'
|
||||||
|
|
||||||
|
|
|
@ -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只保存文本内容')
|
|
@ -0,0 +1,9 @@
|
||||||
|
from rest_framework.serializers import ModelSerializer
|
||||||
|
|
||||||
|
from .models import Workflow
|
||||||
|
|
||||||
|
|
||||||
|
class WorkflowSerializer(ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = Workflow
|
||||||
|
fields = '__all__'
|
|
@ -0,0 +1,3 @@
|
||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
# Create your tests here.
|
|
@ -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)),
|
||||||
|
]
|
||||||
|
|
|
@ -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']
|
|
@ -7,5 +7,6 @@ django-simple-history==3.0.0
|
||||||
djangorestframework==3.12.4
|
djangorestframework==3.12.4
|
||||||
djangorestframework-simplejwt==4.7.2
|
djangorestframework-simplejwt==4.7.2
|
||||||
drf-yasg==1.20.0
|
drf-yasg==1.20.0
|
||||||
psycopg2==2.9.1
|
|
||||||
psutil==5.8.0
|
psutil==5.8.0
|
||||||
|
pillow==8.3.1
|
||||||
|
opencv-python==4.5.3.56
|
||||||
|
|
|
@ -49,6 +49,7 @@ INSTALLED_APPS = [
|
||||||
'apps.monitor',
|
'apps.monitor',
|
||||||
'apps.pum',
|
'apps.pum',
|
||||||
'apps.em',
|
'apps.em',
|
||||||
|
'apps.hrm'
|
||||||
]
|
]
|
||||||
|
|
||||||
MIDDLEWARE = [
|
MIDDLEWARE = [
|
||||||
|
@ -196,6 +197,11 @@ CELERYD_MAX_TASKS_PER_CHILD = 100 # 每个worker最多执行300个任务就会
|
||||||
CELERY_TIMEZONE = 'Asia/Shanghai' # 设置时区
|
CELERY_TIMEZONE = 'Asia/Shanghai' # 设置时区
|
||||||
CELERY_ENABLE_UTC = True # 启动时区设置
|
CELERY_ENABLE_UTC = True # 启动时区设置
|
||||||
|
|
||||||
|
# swagger配置
|
||||||
|
SWAGGER_SETTINGS = {
|
||||||
|
'LOGIN_URL':'/api/admin/login/',
|
||||||
|
'LOGOUT_URL':'/api/admin/logout/'
|
||||||
|
}
|
||||||
|
|
||||||
# 日志配置
|
# 日志配置
|
||||||
# 创建日志的路径
|
# 创建日志的路径
|
||||||
|
|
|
@ -25,6 +25,7 @@ from rest_framework.documentation import include_docs_urls
|
||||||
from rest_framework_simplejwt.views import (TokenObtainPairView,
|
from rest_framework_simplejwt.views import (TokenObtainPairView,
|
||||||
TokenRefreshView)
|
TokenRefreshView)
|
||||||
from django.views.generic import TemplateView
|
from django.views.generic import TemplateView
|
||||||
|
from utils.view import GenSignature
|
||||||
|
|
||||||
router = routers.DefaultRouter()
|
router = routers.DefaultRouter()
|
||||||
router.register('', FileViewSet, basename="file")
|
router.register('', FileViewSet, basename="file")
|
||||||
|
@ -58,6 +59,10 @@ urlpatterns = [
|
||||||
path('api/monitor/', include('apps.monitor.urls')),
|
path('api/monitor/', include('apps.monitor.urls')),
|
||||||
path('api/pum/', include('apps.pum.urls')),
|
path('api/pum/', include('apps.pum.urls')),
|
||||||
path('api/em/', include('apps.em.urls')),
|
path('api/em/', include('apps.em.urls')),
|
||||||
|
path('api/hrm/', include('apps.hrm.urls')),
|
||||||
|
|
||||||
|
# 工具
|
||||||
|
path('api/utils/signature/', GenSignature.as_view()),
|
||||||
|
|
||||||
# 前端页面入口
|
# 前端页面入口
|
||||||
path('',TemplateView.as_view(template_name="index.html"))
|
path('',TemplateView.as_view(template_name="index.html"))
|
||||||
|
|
Loading…
Reference in New Issue