From b4de7a5ff969b313224eba5149ebad8392fa4fd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E5=BC=BA?= <1206709430@qq.com> Date: Fri, 26 Feb 2021 00:17:17 +0800 Subject: [PATCH] =?UTF-8?q?=E5=90=8E=E7=AB=AF-=E5=AD=97=E5=85=B8=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E3=80=81=E8=8F=9C=E5=8D=95=E7=AE=A1=E7=90=86=E5=AE=8C?= =?UTF-8?q?=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dvadmin-backend/apps/op_drf/serializers.py | 4 ++ dvadmin-backend/apps/permission/filters.py | 9 +++ .../apps/permission/models/dept.py | 20 +++--- .../apps/permission/models/menu.py | 38 ++++++------ .../apps/permission/models/post.py | 15 ++--- .../apps/permission/models/role.py | 21 ++++--- .../apps/permission/models/users.py | 31 +++++----- .../apps/permission/serializers.py | 62 +++++++++++++++++-- dvadmin-backend/apps/permission/urls.py | 13 ++++ dvadmin-backend/apps/permission/views.py | 58 +++++++++++++++-- dvadmin-backend/apps/system/__init__.py | 0 dvadmin-backend/apps/system/admin.py | 0 dvadmin-backend/apps/system/apps.py | 6 ++ dvadmin-backend/apps/system/filters.py | 16 +++++ .../apps/system/models/__init__.py | 4 ++ .../apps/system/models/config_settings.py | 21 +++++++ .../apps/system/models/dict_data.py | 17 +++++ .../apps/system/models/dict_details.py | 20 ++++++ dvadmin-backend/apps/system/models/web_set.py | 19 ++++++ dvadmin-backend/apps/system/serializers.py | 47 ++++++++++++++ dvadmin-backend/apps/system/tasks.py | 0 dvadmin-backend/apps/system/tests.py | 3 + dvadmin-backend/apps/system/urls.py | 12 ++++ dvadmin-backend/apps/system/views.py | 60 ++++++++++++++++++ dvadmin-backend/utils/exceptions.py | 16 +++-- 25 files changed, 438 insertions(+), 74 deletions(-) create mode 100644 dvadmin-backend/apps/system/__init__.py create mode 100644 dvadmin-backend/apps/system/admin.py create mode 100644 dvadmin-backend/apps/system/apps.py create mode 100644 dvadmin-backend/apps/system/filters.py create mode 100644 dvadmin-backend/apps/system/models/__init__.py create mode 100644 dvadmin-backend/apps/system/models/config_settings.py create mode 100644 dvadmin-backend/apps/system/models/dict_data.py create mode 100644 dvadmin-backend/apps/system/models/dict_details.py create mode 100644 dvadmin-backend/apps/system/models/web_set.py create mode 100644 dvadmin-backend/apps/system/serializers.py create mode 100644 dvadmin-backend/apps/system/tasks.py create mode 100644 dvadmin-backend/apps/system/tests.py create mode 100644 dvadmin-backend/apps/system/urls.py create mode 100644 dvadmin-backend/apps/system/views.py diff --git a/dvadmin-backend/apps/op_drf/serializers.py b/dvadmin-backend/apps/op_drf/serializers.py index ef693f6..02b1bc9 100644 --- a/dvadmin-backend/apps/op_drf/serializers.py +++ b/dvadmin-backend/apps/op_drf/serializers.py @@ -1,3 +1,4 @@ +from rest_framework import serializers from rest_framework.serializers import ModelSerializer from rest_framework.fields import empty from rest_framework.request import Request @@ -14,6 +15,9 @@ class CustomModelSerializer(ModelSerializer): modifier_field_name = 'modifier' # 创建人的审计字段名称, 默认creator, 继承使用时可自定义覆盖 creator_field_name = 'creator' + # 添加默认时间返回格式 + create_datetime = serializers.DateTimeField(format="%Y-%m-%d %H:%M:%S", required=False, read_only=True) + update_datetime = serializers.DateTimeField(format="%Y-%m-%d %H:%M:%S", required=False, read_only=True) def __init__(self, instance=None, data=empty, request=None, **kwargs): super().__init__(instance, data, **kwargs) diff --git a/dvadmin-backend/apps/permission/filters.py b/dvadmin-backend/apps/permission/filters.py index e69de29..aa876a3 100644 --- a/dvadmin-backend/apps/permission/filters.py +++ b/dvadmin-backend/apps/permission/filters.py @@ -0,0 +1,9 @@ +import django_filters + +from apps.permission.models import Menu + + +class MenuFilter(django_filters.rest_framework.FilterSet): + class Meta: + model = Menu + fields = '__all__' diff --git a/dvadmin-backend/apps/permission/models/dept.py b/dvadmin-backend/apps/permission/models/dept.py index b933130..425ab85 100644 --- a/dvadmin-backend/apps/permission/models/dept.py +++ b/dvadmin-backend/apps/permission/models/dept.py @@ -1,17 +1,17 @@ -from django.db.models import SET_DEFAULT +from django.db.models import CASCADE +from django.db.models import CharField, IntegerField, BooleanField, ForeignKey -from utils import fields -from utils.BaseModels import CoreModel +from apps.op_drf.models import CoreModel class Dept(CoreModel): - name = fields.CharField(null=False, max_length=64, verbose_name="部门名称") - orderNum = fields.IntegerField(verbose_name="显示排序") - owner = fields.CharField(max_length=32, verbose_name="负责人") - phone = fields.CharField(max_length=32, verbose_name="联系电话") - email = fields.CharField(max_length=32, verbose_name="邮箱") - status = fields.BooleanField(default=False, verbose_name="部门状态") - parentId = fields.ForeignKey(to='Dept', on_delete=SET_DEFAULT, default=False, verbose_name="上级部门") + name = CharField(max_length=64, verbose_name="部门名称") + orderNum = IntegerField(verbose_name="显示排序") + owner = CharField(max_length=32, verbose_name="负责人", null=True) + phone = CharField(max_length=32, verbose_name="联系电话", null=True) + email = CharField(max_length=32, verbose_name="邮箱", null=True) + status = BooleanField(default=False, verbose_name="部门状态") + parentId = ForeignKey(to='Dept', on_delete=CASCADE, default=False, verbose_name="上级部门") class Meta: verbose_name = '部门管理' diff --git a/dvadmin-backend/apps/permission/models/menu.py b/dvadmin-backend/apps/permission/models/menu.py index f40c8cf..ba46103 100644 --- a/dvadmin-backend/apps/permission/models/menu.py +++ b/dvadmin-backend/apps/permission/models/menu.py @@ -1,14 +1,13 @@ -from django.db.models import SET_DEFAULT +from django.db.models import IntegerField, BooleanField, ForeignKey, CharField, CASCADE -from utils import fields -from utils.BaseModels import CoreModel +from apps.op_drf.models import CoreModel class Menu(CoreModel): MENU_TYPE_CHOICES = ( - (0, "目录"), - (1, "菜单"), - (2, "按钮"), + ("0", "目录"), + ("1", "菜单"), + ("2", "按钮"), ) METHOD_CHOICE = ( ('GET', 'GET'), @@ -20,19 +19,20 @@ class Menu(CoreModel): ('OPTIONS', 'OPTIONS'), ('TRACE', 'TRACE'), ) - name = fields.CharField(null=False, max_length=64, verbose_name="菜单名称") - icon = fields.CharField(max_length=64, verbose_name="菜单图标") - orderNum = fields.IntegerField(verbose_name="显示排序") - menuType = fields.IntegerField(choices=MENU_TYPE_CHOICES, verbose_name="菜单类型") - status = fields.BooleanField(default=False, verbose_name="菜单状态") - visible = fields.BooleanField(default=False, verbose_name="显示状态") - isFrame = fields.BooleanField(default=False, verbose_name="是否外链") - web_path = fields.CharField(max_length=128, verbose_name="前端路由地址") - component_path = fields.CharField(max_length=128, verbose_name="组件路径") - interface_path = fields.CharField(max_length=256, verbose_name="接口路径") - interface_method = fields.CharField(choices=METHOD_CHOICE, max_length=16, verbose_name="接口请求方式") - isCache = fields.BooleanField(default=False, verbose_name="是否外链") - parentId = fields.ForeignKey(to='Menu', on_delete=SET_DEFAULT, default=False, verbose_name="上级菜单") + parentId = ForeignKey(to='Menu', on_delete=CASCADE, null=True, verbose_name="上级菜单") + menuType = CharField(max_length=8,choices=MENU_TYPE_CHOICES, verbose_name="菜单类型") + icon = CharField(max_length=64, verbose_name="菜单图标", null=True) + name = CharField(max_length=64, verbose_name="菜单名称") + orderNum = IntegerField(verbose_name="显示排序") + isFrame = CharField(max_length=8,verbose_name="是否外链") + web_path = CharField(max_length=128, verbose_name="前端路由地址", null=True) + component_path = CharField(max_length=128, verbose_name="前端组件路径", null=True) + interface_path = CharField(max_length=256, verbose_name="后端接口路径", null=True) + interface_method = CharField(choices=METHOD_CHOICE, max_length=16, default='GET', verbose_name="接口请求方式") + perms = CharField(max_length=256, verbose_name="权限标识", null=True) + status = CharField(max_length=8,verbose_name="菜单状态") + visible = CharField(max_length=8,verbose_name="显示状态") + isCache = CharField(max_length=8, verbose_name="是否缓存") class Meta: verbose_name = '菜单管理' diff --git a/dvadmin-backend/apps/permission/models/post.py b/dvadmin-backend/apps/permission/models/post.py index 932e0be..0fde398 100644 --- a/dvadmin-backend/apps/permission/models/post.py +++ b/dvadmin-backend/apps/permission/models/post.py @@ -1,13 +1,14 @@ -from utils import fields -from utils.BaseModels import CoreModel +from django.db.models import IntegerField, BooleanField, CharField, TextField + +from apps.op_drf.models import CoreModel class Post(CoreModel): - name = fields.CharField(null=False, max_length=64, verbose_name="岗位名称") - web_path = fields.CharField(max_length=32, verbose_name="岗位编码") - orderNum = fields.IntegerField(verbose_name="岗位顺序") - status = fields.BooleanField(default=False, verbose_name="岗位状态") - remark = fields.TextField(verbose_name="备注", help_text="备注") + name = CharField(null=False, max_length=64, verbose_name="岗位名称") + web_path = CharField(max_length=32, verbose_name="岗位编码") + orderNum = IntegerField(verbose_name="岗位顺序") + status = BooleanField(default=False, verbose_name="岗位状态") + remark = TextField(verbose_name="备注", help_text="备注", null=True) class Meta: verbose_name = '岗位管理' diff --git a/dvadmin-backend/apps/permission/models/role.py b/dvadmin-backend/apps/permission/models/role.py index 9073373..3e42c56 100644 --- a/dvadmin-backend/apps/permission/models/role.py +++ b/dvadmin-backend/apps/permission/models/role.py @@ -1,5 +1,6 @@ -from utils import fields -from utils.BaseModels import CoreModel +from django.db.models import IntegerField, BooleanField, CharField, TextField, ManyToManyField + +from apps.op_drf.models import CoreModel class Role(CoreModel): @@ -10,13 +11,15 @@ class Role(CoreModel): (3, "本部门及以下数据权限"), (4, "仅本人数据权限"), ) - name = fields.CharField(null=False, max_length=64, verbose_name="角色名称") - orderNum = fields.IntegerField(verbose_name="角色顺序") - status = fields.BooleanField(default=False, verbose_name="角色状态") - purview = fields.IntegerField(default=0, choices=PURVIEW_CHOICES, verbose_name="权限范围") - remark = fields.TextField(verbose_name="备注", help_text="备注") - dept = fields.ManyToManyField(to='Dept', verbose_name='数据权限-关联部门') - menu = fields.ManyToManyField(to='Menu', verbose_name='关联菜单权限') + name = CharField(max_length=64, verbose_name="角色名称") + roleKey = CharField(max_length=64, verbose_name="权限字符") + orderNum = IntegerField(verbose_name="角色顺序") + status = BooleanField(default=False, verbose_name="角色状态") + admin = BooleanField(default=False, verbose_name="是否为admin") + purview = IntegerField(default=0, choices=PURVIEW_CHOICES, verbose_name="权限范围") + remark = TextField(verbose_name="备注", help_text="备注", null=True) + dept = ManyToManyField(to='Dept', verbose_name='数据权限-关联部门') + menu = ManyToManyField(to='Menu', verbose_name='关联菜单权限') class Meta: verbose_name = '角色管理' diff --git a/dvadmin-backend/apps/permission/models/users.py b/dvadmin-backend/apps/permission/models/users.py index 51a36de..7733482 100644 --- a/dvadmin-backend/apps/permission/models/users.py +++ b/dvadmin-backend/apps/permission/models/users.py @@ -1,8 +1,9 @@ from uuid import uuid4 from django.contrib.auth.models import UserManager, AbstractUser +from django.db.models import IntegerField, ForeignKey, CharField, TextField, ManyToManyField, CASCADE -from utils import fields +from apps.op_drf.fields import CreateDateTimeField, UpdateDateTimeField class UserProfile(AbstractUser): @@ -16,20 +17,20 @@ class UserProfile(AbstractUser): (1, "前台用户"), ) objects = UserManager() - username = fields.CharField(max_length=150, unique=True, db_index=True, verbose_name='用户账号') - secret = fields.CharField(max_length=255, default=uuid4, verbose_name='加密秘钥') - email = fields.CharField(max_length=255, verbose_name="邮箱") - mobile = fields.CharField(max_length=255, verbose_name="电话") - avatar = fields.TextField(verbose_name="头像") - name = fields.CharField(max_length=40, verbose_name="姓名") - gender = fields.IntegerField(default=2, choices=GENDER_CHOICES, verbose_name="性别") - remark = fields.TextField(verbose_name="备注") - user_type = fields.IntegerField(default=2, choices=GENDER_CHOICES, verbose_name="用户类型") - post = fields.ForeignKey(to='Post', verbose_name='关联岗位') - role = fields.ForeignKey(to='Role', verbose_name='关联角色') - dept = fields.ForeignKey(to='Dept', verbose_name='归属部门') - create_datetime = fields.CreateDateTimeField() - update_datetime = fields.UpdateDateTimeField() + username = CharField(max_length=150, unique=True, db_index=True, verbose_name='用户账号') + secret = CharField(max_length=255, default=uuid4, verbose_name='加密秘钥') + email = CharField(max_length=255, verbose_name="邮箱", null=True) + mobile = CharField(max_length=255, verbose_name="电话", null=True) + avatar = TextField(verbose_name="头像") + name = CharField(max_length=40, verbose_name="姓名") + gender = IntegerField(default=2, choices=GENDER_CHOICES, verbose_name="性别") + remark = TextField(verbose_name="备注", null=True) + user_type = IntegerField(default=2, choices=GENDER_CHOICES, verbose_name="用户类型") + post = ManyToManyField(to='Post', verbose_name='关联岗位') + role = ManyToManyField(to='Role', verbose_name='关联角色') + dept = ForeignKey(to='Dept', verbose_name='归属部门', on_delete=CASCADE, null=True) + create_datetime = CreateDateTimeField() + update_datetime = UpdateDateTimeField() class Meta: verbose_name = '用户管理' diff --git a/dvadmin-backend/apps/permission/serializers.py b/dvadmin-backend/apps/permission/serializers.py index 1435bb2..383a6cc 100644 --- a/dvadmin-backend/apps/permission/serializers.py +++ b/dvadmin-backend/apps/permission/serializers.py @@ -1,10 +1,64 @@ from rest_framework import serializers -from apps.permission.models import UserProfile +from apps.op_drf.serializers import CustomModelSerializer +from apps.permission.models import UserProfile, Menu, Role -class GetUserInfoSerializer(serializers.ModelSerializer): +class UserProfileSerializer(CustomModelSerializer): + """ + 简单用户序列化器 + """ + admin = serializers.SerializerMethodField(read_only=True) + + def get_admin(self, obj: UserProfile): + role_list = obj.role.all().values_list('admin', flat=True) + if True in list(set(role_list)): + return True + return False + class Meta: model = UserProfile - fields = ( - 'username',) + dept = 2 + exclude = ('password', 'secret', 'user_permissions', 'groups', 'is_superuser', 'date_joined') + + +class MenuSerializer(CustomModelSerializer): + """ + 简单菜单序列化器 + """ + parentId = serializers.IntegerField(source="parentId.id", default=0) + class Meta: + model = Menu + fields = '__all__' + + +class CreateUpdateMenuSerializer(CustomModelSerializer): + """ + 创建角色/更新时的列化器 + """ + + def validate(self, attrs: dict): + # name = attrs['name'] + # role: Role = Role.objects.filter(name=name).first() + # if role and attrs.get('instanceId', '') != role.instanceId: + # raise APIException(message=f'角色名称[{name}]不能重复') + # if getattr(self.instance, 'is_public', False) or attrs.get('is_public', False): + # up = UserPermission(self.request.user) + # if not up.is_manager(): + # raise APIException(message=f'仅Manger能创建/更新角色为公共角色') + return super().validate(attrs) + + class Meta: + model = Menu + fields = "__all__" + read_only_fields = ('mtime', 'ctime', 'creator', 'modifier') + + +class RoleSerializer(serializers.ModelSerializer): + """ + 简单角色序列化器 + """ + + class Meta: + model = Role + fields = '__all__' diff --git a/dvadmin-backend/apps/permission/urls.py b/dvadmin-backend/apps/permission/urls.py index e69de29..50b1c0a 100644 --- a/dvadmin-backend/apps/permission/urls.py +++ b/dvadmin-backend/apps/permission/urls.py @@ -0,0 +1,13 @@ +from django.urls import re_path +from rest_framework.routers import DefaultRouter + +from apps.permission.views import MenuModelViewSet + +router = DefaultRouter() +router.register(r'menus', MenuModelViewSet) +urlpatterns = [ + + # re_path('menus/', MenuModelViewSet.as_view({'get': 'list'}), name='api_token_auth'), + +] +urlpatterns += router.urls diff --git a/dvadmin-backend/apps/permission/views.py b/dvadmin-backend/apps/permission/views.py index 607f508..8b02cfa 100644 --- a/dvadmin-backend/apps/permission/views.py +++ b/dvadmin-backend/apps/permission/views.py @@ -3,17 +3,29 @@ import json from rest_framework.response import Response from rest_framework.views import APIView +from apps.op_drf.viewsets import CustomModelViewSet +from apps.permission.filters import MenuFilter +from apps.permission.models import Role, Menu +from apps.permission.serializers import UserProfileSerializer, MenuSerializer, RoleSerializer, \ + CreateUpdateMenuSerializer +from utils.response import SuccessResponse -class GetUserView(APIView): + +class GetUserProfileView(APIView): """ 获取用户详细信息 """ def get(self, request, format=None): - # data = GetUserInfoSerializer(request.user).data - data = '{"msg":"操作成功","code":200,"permissions":["*:*:*"],"roles":["admin"],"user":{"searchValue":null,"createBy":"admin","createTime":"2020-11-20 19:29:42","updateBy":null,"updateTime":null,"remark":"管理员","params":{},"userId":1,"deptId":103,"userName":"admin","nickName":"若依","email":"ry@163.com","phonenumber":"15888888888","sex":"1","avatar":"","salt":null,"status":"0","delFlag":"0","loginIp":"127.0.0.1","loginDate":"2020-11-20T19:29:42.000+0800","dept":{"searchValue":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"remark":null,"params":{},"deptId":103,"parentId":101,"ancestors":null,"deptName":"研发部门","orderNum":"1","leader":"若依","phone":null,"email":null,"status":"0","delFlag":null,"parentName":null,"children":[]},"roles":[{"searchValue":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"remark":null,"params":{},"roleId":1,"roleName":"超级管理员","roleKey":"admin","roleSort":"1","dataScope":"1","menuCheckStrictly":false,"deptCheckStrictly":false,"status":"0","delFlag":null,"flag":false,"menuIds":null,"deptIds":null,"admin":true}],"roleIds":null,"postIds":null,"admin":true}}' - data = json.loads(data) - return Response(data) + user_dict = UserProfileSerializer(request.user).data + + return SuccessResponse({ + 'permissions': ["*:*:*"] if not user_dict.get('admin') else Menu.objects.filter( + role__userprofile=request.user).values_list('perms', flat=True), + # 'roles': Role.objects.filter(userprofile=request.user).values_list('roleKey', flat=True), + 'roles': ['admin'], + 'user': user_dict + }) class GetRouters(APIView): @@ -26,3 +38,39 @@ class GetRouters(APIView): data = '{"msg":"操作成功","code":200,"data":[{"name":"System","path":"/system","hidden":false,"redirect":"noRedirect","component":"Layout","alwaysShow":true,"meta":{"title":"系统管理","icon":"system","noCache":false},"children":[{"name":"User","path":"user","hidden":false,"component":"system/user/index","meta":{"title":"用户管理","icon":"user","noCache":false}},{"name":"Role","path":"role","hidden":false,"component":"system/role/index","meta":{"title":"角色管理","icon":"peoples","noCache":false}},{"name":"Menu","path":"menu","hidden":false,"component":"system/menu/index","meta":{"title":"菜单管理","icon":"tree-table","noCache":false}},{"name":"Dept","path":"dept","hidden":false,"component":"system/dept/index","meta":{"title":"部门管理","icon":"tree","noCache":false}},{"name":"Post","path":"post","hidden":false,"component":"system/post/index","meta":{"title":"岗位管理","icon":"post","noCache":false}},{"name":"Dict","path":"dict","hidden":false,"component":"system/dict/index","meta":{"title":"字典管理","icon":"dict","noCache":false}},{"name":"Config","path":"config","hidden":false,"component":"system/config/index","meta":{"title":"参数设置","icon":"edit","noCache":false}},{"name":"Notice","path":"notice","hidden":false,"component":"system/notice/index","meta":{"title":"通知公告","icon":"message","noCache":false}},{"name":"Log","path":"log","hidden":false,"redirect":"noRedirect","component":"ParentView","alwaysShow":true,"meta":{"title":"日志管理","icon":"log","noCache":false},"children":[{"name":"Operlog","path":"operlog","hidden":false,"component":"monitor/operlog/index","meta":{"title":"操作日志","icon":"form","noCache":false}},{"name":"Logininfor","path":"logininfor","hidden":false,"component":"monitor/logininfor/index","meta":{"title":"登录日志","icon":"logininfor","noCache":false}}]}]},{"name":"Monitor","path":"/monitor","hidden":false,"redirect":"noRedirect","component":"Layout","alwaysShow":true,"meta":{"title":"系统监控","icon":"monitor","noCache":false},"children":[{"name":"Online","path":"online","hidden":false,"component":"monitor/online/index","meta":{"title":"在线用户","icon":"online","noCache":false}},{"name":"Job","path":"job","hidden":false,"component":"monitor/job/index","meta":{"title":"定时任务","icon":"job","noCache":false}},{"name":"Druid","path":"druid","hidden":false,"component":"monitor/druid/index","meta":{"title":"数据监控","icon":"druid","noCache":false}},{"name":"Server","path":"server","hidden":false,"component":"monitor/server/index","meta":{"title":"服务监控","icon":"server","noCache":false}},{"name":"Cache","path":"cache","hidden":false,"component":"monitor/cache/index","meta":{"title":"缓存监控","icon":"redis","noCache":false}}]},{"name":"Tool","path":"/tool","hidden":false,"redirect":"noRedirect","component":"Layout","alwaysShow":true,"meta":{"title":"系统工具","icon":"tool","noCache":false},"children":[{"name":"Build","path":"build","hidden":false,"component":"tool/build/index","meta":{"title":"表单构建","icon":"build","noCache":false}},{"name":"Gen","path":"gen","hidden":false,"component":"tool/gen/index","meta":{"title":"代码生成","icon":"code","noCache":false}},{"name":"Swagger","path":"swagger","hidden":false,"component":"tool/swagger/index","meta":{"title":"系统接口","icon":"swagger","noCache":false}}]},{"name":"Http://ruoyi.vip","path":"http://ruoyi.vip","hidden":false,"component":"Layout","meta":{"title":"若依官网","icon":"guide","noCache":false}}]}' data = json.loads(data) return Response(data) + + +class MenuModelViewSet(CustomModelViewSet): + """ + 菜单模型的CRUD视图 + """ + queryset = Menu.objects.all() + serializer_class = MenuSerializer + create_serializer_class = CreateUpdateMenuSerializer + update_serializer_class = CreateUpdateMenuSerializer + # list_serializer_class = ListRoleSerializer + # retrieve_serializer_class = DetailRoleSerializer + filter_class = MenuFilter + # update_extra_permission_classes = (IsManagerPermission,) + # destroy_extra_permission_classes = (IsManagerPermission,) + # create_extra_permission_classes = (IsManagerPermission,) + search_fields = ('name',) + ordering = 'create_datetime' # 默认排序 + + +class RoleModelViewSet(CustomModelViewSet): + """ + 角色模型的CRUD视图 + """ + queryset = Role.objects.all() + serializer_class = RoleSerializer + # create_serializer_class = CreateUpdateRoleSerializer + # update_serializer_class = CreateUpdateRoleSerializer + # list_serializer_class = ListRoleSerializer + # retrieve_serializer_class = DetailRoleSerializer + # filter_class = RoleFilter + # update_extra_permission_classes = (IsManagerPermission,) + # destroy_extra_permission_classes = (IsManagerPermission,) + # create_extra_permission_classes = (IsManagerPermission,) + search_fields = ('name',) + ordering = 'create_datetime' # 默认排序 diff --git a/dvadmin-backend/apps/system/__init__.py b/dvadmin-backend/apps/system/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/dvadmin-backend/apps/system/admin.py b/dvadmin-backend/apps/system/admin.py new file mode 100644 index 0000000..e69de29 diff --git a/dvadmin-backend/apps/system/apps.py b/dvadmin-backend/apps/system/apps.py new file mode 100644 index 0000000..2f171f9 --- /dev/null +++ b/dvadmin-backend/apps/system/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class PermissionConfig(AppConfig): + name = 'system' + verbose_name = "权限管理" diff --git a/dvadmin-backend/apps/system/filters.py b/dvadmin-backend/apps/system/filters.py new file mode 100644 index 0000000..eda565d --- /dev/null +++ b/dvadmin-backend/apps/system/filters.py @@ -0,0 +1,16 @@ +import django_filters + +from apps.system.models import DictDetails, DictData + + +class DictDataFilter(django_filters.rest_framework.FilterSet): + class Meta: + model = DictData + fields = '__all__' + + +class DictDetailsFilter(django_filters.rest_framework.FilterSet): + dictType = django_filters.CharFilter(field_name='dict_data__dictType') + class Meta: + model = DictDetails + fields = '__all__' diff --git a/dvadmin-backend/apps/system/models/__init__.py b/dvadmin-backend/apps/system/models/__init__.py new file mode 100644 index 0000000..98f83d0 --- /dev/null +++ b/dvadmin-backend/apps/system/models/__init__.py @@ -0,0 +1,4 @@ +from ..models.config_settings import ConfigSettings +from ..models.dict_data import DictData +from ..models.dict_details import DictDetails +from ..models.web_set import WebSet diff --git a/dvadmin-backend/apps/system/models/config_settings.py b/dvadmin-backend/apps/system/models/config_settings.py new file mode 100644 index 0000000..d007348 --- /dev/null +++ b/dvadmin-backend/apps/system/models/config_settings.py @@ -0,0 +1,21 @@ +from django.db.models import CharField, ForeignKey, BooleanField, CASCADE + +from apps.op_drf.models import CoreModel + + +class ConfigSettings(CoreModel): + name = CharField(max_length=64, verbose_name="参数名称") + configKey = CharField(max_length=256, verbose_name="参数键名") + configValue = CharField(max_length=256, verbose_name="参数键值") + configType = BooleanField(default=False,verbose_name="是否内置") + is_status = BooleanField(default=False, verbose_name="字典状态") + sort = CharField(max_length=256, verbose_name="字典排序") + dict_data = ForeignKey(to='DictData', on_delete=CASCADE, verbose_name="关联字典") + remark = CharField(max_length=256, verbose_name="备注", null=True) + + class Meta: + verbose_name = '参数设置' + verbose_name_plural = verbose_name + + def __str__(self): + return f"{self.name}" diff --git a/dvadmin-backend/apps/system/models/dict_data.py b/dvadmin-backend/apps/system/models/dict_data.py new file mode 100644 index 0000000..905c807 --- /dev/null +++ b/dvadmin-backend/apps/system/models/dict_data.py @@ -0,0 +1,17 @@ +from django.db.models import TextField, CharField,ForeignKey + +from apps.op_drf.models import CoreModel + + +class DictData(CoreModel): + name = CharField(max_length=64, verbose_name="字典名称") + dictType = CharField(max_length=64, verbose_name="字典类型") + status = CharField(max_length=8, verbose_name="字典状态") + remark = CharField(max_length=256,verbose_name="备注", null=True) + + class Meta: + verbose_name = '字典管理' + verbose_name_plural = verbose_name + + def __str__(self): + return f"{self.name}" diff --git a/dvadmin-backend/apps/system/models/dict_details.py b/dvadmin-backend/apps/system/models/dict_details.py new file mode 100644 index 0000000..ec32409 --- /dev/null +++ b/dvadmin-backend/apps/system/models/dict_details.py @@ -0,0 +1,20 @@ +from django.db.models import CharField, ForeignKey, BooleanField, CASCADE + +from apps.op_drf.models import CoreModel + + +class DictDetails(CoreModel): + name = CharField(max_length=64, verbose_name="字典标签") + dictValue = CharField(max_length=256, verbose_name="字典键值") + is_default = BooleanField(verbose_name="是否默认", default=False) + status = CharField(max_length=2, verbose_name="字典状态") + sort = CharField(max_length=256, verbose_name="字典排序") + dict_data = ForeignKey(to='DictData', on_delete=CASCADE, verbose_name="关联字典") + remark = CharField(max_length=256, verbose_name="备注", null=True) + + class Meta: + verbose_name = '字典详情' + verbose_name_plural = verbose_name + + def __str__(self): + return f"{self.name}" diff --git a/dvadmin-backend/apps/system/models/web_set.py b/dvadmin-backend/apps/system/models/web_set.py new file mode 100644 index 0000000..0b11962 --- /dev/null +++ b/dvadmin-backend/apps/system/models/web_set.py @@ -0,0 +1,19 @@ +from django.db.models import TextField, CharField + +from apps.op_drf.models import CoreModel + + +class WebSet(CoreModel): + name = CharField(max_length=64, verbose_name="站点名称") + web_site = CharField(max_length=256, verbose_name="站点网址", null=True) + logo = CharField(max_length=256, verbose_name="网站Logo", null=True) + record_info = TextField(verbose_name="备案信息", null=True) + statistics_code = TextField(verbose_name="统计代码", null=True) + copyright_info = TextField(verbose_name="版权信息", null=True) + + class Meta: + verbose_name = '站点设置' + verbose_name_plural = verbose_name + + def __str__(self): + return f"{self.name}" diff --git a/dvadmin-backend/apps/system/serializers.py b/dvadmin-backend/apps/system/serializers.py new file mode 100644 index 0000000..65ab62c --- /dev/null +++ b/dvadmin-backend/apps/system/serializers.py @@ -0,0 +1,47 @@ +from rest_framework import serializers + +from apps.op_drf.serializers import CustomModelSerializer +from apps.system.models import DictData, DictDetails + + +class DictDataSerializer(serializers.ModelSerializer): + """ + 字典管理 简单序列化器 + """ + + class Meta: + model = DictData + exclude = ('description', 'creator', 'modifier') + + +class DictDataCreateUpdateSerializer(CustomModelSerializer): + """ + 字典管理 创建/更新时的列化器 + """ + + class Meta: + model = DictData + fields = "__all__" + read_only_fields = ('update_datetime', 'create_datetime', 'creator', 'modifier') + + +class DictDetailsSerializer(serializers.ModelSerializer): + """ + 字典详情 简单序列化器 + """ + dictType = serializers.CharField(source='dict_data.dictType', default='', read_only=True) + + class Meta: + model = DictDetails + exclude = ('creator', 'modifier') + + +class DictDetailsCreateUpdateSerializer(CustomModelSerializer): + """ + 字典详情 创建/更新时的列化器 + """ + + class Meta: + model = DictDetails + fields = "__all__" + read_only_fields = ('update_datetime', 'create_datetime', 'creator', 'modifier') diff --git a/dvadmin-backend/apps/system/tasks.py b/dvadmin-backend/apps/system/tasks.py new file mode 100644 index 0000000..e69de29 diff --git a/dvadmin-backend/apps/system/tests.py b/dvadmin-backend/apps/system/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/dvadmin-backend/apps/system/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/dvadmin-backend/apps/system/urls.py b/dvadmin-backend/apps/system/urls.py new file mode 100644 index 0000000..885ae83 --- /dev/null +++ b/dvadmin-backend/apps/system/urls.py @@ -0,0 +1,12 @@ +from django.urls import re_path +from rest_framework.routers import DefaultRouter + +from apps.system.views import DictDataModelViewSet, DictDetailsModelViewSet, DictDetailsListModelViewSet + +router = DefaultRouter() +router.register(r'dict/type', DictDataModelViewSet) +router.register(r'dict/data', DictDetailsModelViewSet) +router.register(r'dict/get/type', DictDetailsListModelViewSet) +urlpatterns = [ +] +urlpatterns += router.urls diff --git a/dvadmin-backend/apps/system/views.py b/dvadmin-backend/apps/system/views.py new file mode 100644 index 0000000..e204511 --- /dev/null +++ b/dvadmin-backend/apps/system/views.py @@ -0,0 +1,60 @@ +from rest_framework.request import Request + +from apps.op_drf.viewsets import CustomModelViewSet +from apps.system.models import DictData +from apps.system.serializers import DictDataSerializer, DictDataCreateUpdateSerializer, DictDetailsSerializer, \ + DictDetailsCreateUpdateSerializer +from apps.system.models import DictDetails +from apps.system.filters import DictDetailsFilter, DictDataFilter +from utils.response import SuccessResponse + + +class DictDataModelViewSet(CustomModelViewSet): + """ + 字典管理模型的CRUD视图 + """ + queryset = DictData.objects.all() + serializer_class = DictDataSerializer + create_serializer_class = DictDataCreateUpdateSerializer + # update_serializer_class = CreateUpdateRoleSerializer + # list_serializer_class = ListRoleSerializer + # retrieve_serializer_class = DetailRoleSerializer + filter_class = DictDataFilter + # update_extra_permission_classes = (IsManagerPermission,) + # destroy_extra_permission_classes = (IsManagerPermission,) + # create_extra_permission_classes = (IsManagerPermission,) + search_fields = ('name',) + ordering = 'id' # 默认排序 + +class DictDetailsModelViewSet(CustomModelViewSet): + """ + 字典详情 模型的CRUD视图 + """ + queryset = DictDetails.objects.all() + serializer_class = DictDetailsSerializer + create_serializer_class = DictDetailsCreateUpdateSerializer + # update_serializer_class = CreateUpdateRoleSerializer + # list_serializer_class = ListRoleSerializer + # retrieve_serializer_class = DetailRoleSerializer + filter_class = DictDetailsFilter + # update_extra_permission_classes = (IsManagerPermission,) + # destroy_extra_permission_classes = (IsManagerPermission,) + # create_extra_permission_classes = (IsManagerPermission,) + search_fields = ('name',) + ordering = 'sort' # 默认排序 + +class DictDetailsListModelViewSet(CustomModelViewSet): + """ + 根据字典类型查询字典数据信息 模型的CRUD视图 + """ + queryset = DictDetails.objects.filter(status=True) + serializer_class = DictDetailsSerializer + filter_class = DictDetailsFilter + search_fields = ('name',) + ordering = 'create_datetime' # 默认排序 + def list(self, request: Request, *args, **kwargs): + queryset = self.filter_queryset(self.get_queryset()) + if hasattr(self, 'handle_logging'): + self.handle_logging(request, *args, **kwargs) + serializer = self.get_serializer(queryset, many=True) + return SuccessResponse(serializer.data) diff --git a/dvadmin-backend/utils/exceptions.py b/dvadmin-backend/utils/exceptions.py index 86ef46e..c6969b7 100644 --- a/dvadmin-backend/utils/exceptions.py +++ b/dvadmin-backend/utils/exceptions.py @@ -1,11 +1,13 @@ import logging import traceback +from rest_framework import serializers, exceptions + from .response import ErrorResponse logger = logging.getLogger(__name__) -from rest_framework.exceptions import APIException as DRFAPIException +from rest_framework.exceptions import APIException as DRFAPIException, AuthenticationFailed class APIException(Exception): @@ -60,12 +62,16 @@ def op_exception_handler(ex, context): :return: """ msg = '' - if isinstance(ex, DRFAPIException): + code = '201' + if isinstance(ex, AuthenticationFailed): + code = 401 + msg = ex.detail + elif isinstance(ex, DRFAPIException): # set_rollback() msg = ex.detail - elif isinstance(ex, APIException): - msg = ex.message + elif isinstance(ex, exceptions.APIException): + msg = ex.detail elif isinstance(ex, Exception): logger.error(traceback.format_exc()) msg = str(ex) - return ErrorResponse(msg=msg) + return ErrorResponse(msg=msg,code=code)