From 8c8b38817c32648067d6e65daa665270c4ecab41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E5=BC=BA?= <1206709430@qq.com> Date: Sat, 14 May 2022 00:11:25 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8A=9F=E8=83=BD=E5=8F=98=E5=8C=96:=20?= =?UTF-8?q?=E5=90=8E=E7=AB=AF=E8=8E=B7=E5=8F=96=E7=B3=BB=E7=BB=9F=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/application/settings.py | 5 +- backend/application/urls.py | 72 ++++++++-------- backend/conf/env.example.py | 5 -- backend/dvadmin/system/models.py | 83 ++++++++++++++++++- backend/dvadmin/system/views/dictionary.py | 26 +----- backend/dvadmin/system/views/login.py | 25 ++---- backend/dvadmin/system/views/system_config.py | 15 +--- 7 files changed, 137 insertions(+), 94 deletions(-) diff --git a/backend/application/settings.py b/backend/application/settings.py index 0352a32..c2dfc73 100644 --- a/backend/application/settings.py +++ b/backend/application/settings.py @@ -366,4 +366,7 @@ INITIALIZE_LIST = [] INITIALIZE_RESET_LIST = [] # 表前缀 TABLE_PREFIX = locals().get('TABLE_PREFIX', "") -DEFAULT_PASSWORD = locals().get("DEFAULT_PASSWORD", "admin123456") +# 系统配置 +SYSTEM_CONFIG = {} +# 字典配置 +DICTIONARY_CONFIG = {} diff --git a/backend/application/urls.py b/backend/application/urls.py index 94dc0b0..10ab524 100644 --- a/backend/application/urls.py +++ b/backend/application/urls.py @@ -23,17 +23,22 @@ from rest_framework_simplejwt.views import ( ) from application import settings +from dvadmin.system.models import SystemConfig, Dictionary +from dvadmin.system.views.dictionary import InitDictionaryViewSet from dvadmin.system.views.login import ( LoginView, - CaptchaStatusView, CaptchaView, ApiLogin, LogoutView, ) from dvadmin.system.views.system_config import InitSettingsViewSet -from dvadmin.system.views.dictionary import InitDictionaryViewSet from dvadmin.utils.swagger import CustomOpenAPISchemaGenerator +# =========== 初始化系统配置 ================= +SystemConfig.init_system_config() +Dictionary.init_dictionary() +# =========== 初始化系统配置 ================= + schema_view = get_schema_view( openapi.Info( title="Snippets API", @@ -49,35 +54,36 @@ schema_view = get_schema_view( ) urlpatterns = ( - [ - re_path( - r"^swagger(?P\.json|\.yaml)$", - schema_view.without_ui(cache_timeout=0), - name="schema-json", - ), - path( - "", - schema_view.with_ui("swagger", cache_timeout=0), - name="schema-swagger-ui", - ), - path( - r"redoc/", - schema_view.with_ui("redoc", cache_timeout=0), - name="schema-redoc", - ), - path("api/system/", include("dvadmin.system.urls")), - path("api/login/", LoginView.as_view(), name="token_obtain_pair"), - path("api/logout/", LogoutView.as_view(), name="token_obtain_pair"), - path("token/refresh/", TokenRefreshView.as_view(), name="token_refresh"), - re_path( - r"^api-auth/", include("rest_framework.urls", namespace="rest_framework") - ), - path("api/captcha/", CaptchaView.as_view()), - path("api/captcha/status/", CaptchaStatusView.as_view()), - path("api/init/dictionary/", InitDictionaryViewSet.as_view()), - path("api/init/settings/", InitSettingsViewSet.as_view()), - path("apiLogin/", ApiLogin.as_view()), - ] - + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) - + static(settings.STATIC_URL, document_root=settings.STATIC_URL) + [ + re_path( + r"^swagger(?P\.json|\.yaml)$", + schema_view.without_ui(cache_timeout=0), + name="schema-json", + ), + path( + "", + schema_view.with_ui("swagger", cache_timeout=0), + name="schema-swagger-ui", + ), + path( + r"redoc/", + schema_view.with_ui("redoc", cache_timeout=0), + name="schema-redoc", + ), + path("api/system/", include("dvadmin.system.urls")), + path("api/login/", LoginView.as_view(), name="token_obtain_pair"), + path("api/logout/", LogoutView.as_view(), name="token_obtain_pair"), + path("token/refresh/", TokenRefreshView.as_view(), name="token_refresh"), + re_path( + r"^api-auth/", include("rest_framework.urls", namespace="rest_framework") + ), + path("api/captcha/", CaptchaView.as_view()), + path("api/init/dictionary/", InitDictionaryViewSet.as_view()), + path("api/init/settings/", InitSettingsViewSet.as_view()), + path("apiLogin/", ApiLogin.as_view()), + re_path(r'api/upgrade_center_backend/', include('dvadmin_upgrade_center.urls')), + re_path(r'api/dvadmin_upgrade_center/', include('dvadmin_upgrade_center.urls')), + ] + + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) + + static(settings.STATIC_URL, document_root=settings.STATIC_URL) ) diff --git a/backend/conf/env.example.py b/backend/conf/env.example.py index 4a7444d..9aed05d 100644 --- a/backend/conf/env.example.py +++ b/backend/conf/env.example.py @@ -37,8 +37,6 @@ TABLE_PREFIX = "sys_" DEBUG = True # 启动登录详细概略获取(通过调用api获取ip详细地址。如果是内网,关闭即可) ENABLE_LOGIN_ANALYSIS_LOG = True -# 是否启用登录验证码,不需要可以设置为False,线上环境建议开启 -CAPTCHA_STATE = True # 登录接口 /api/token/ 是否需要验证码认证,用于测试,正式环境建议取消 LOGIN_NO_CAPTCHA_AUTH = True # ================================================= # @@ -46,6 +44,3 @@ LOGIN_NO_CAPTCHA_AUTH = True # ================================================= # ALLOWED_HOSTS = ["*"] - -# 默认密码 -DEFAULT_PASSWORD = "admin123456" diff --git a/backend/dvadmin/system/models.py b/backend/dvadmin/system/models.py index ae3a249..bb5b3dc 100644 --- a/backend/dvadmin/system/models.py +++ b/backend/dvadmin/system/models.py @@ -1,6 +1,7 @@ import hashlib import os +from django.conf import settings from django.contrib.auth.models import AbstractUser from django.db import models @@ -194,6 +195,35 @@ class Dictionary(CoreModel): verbose_name_plural = verbose_name ordering = ('sort',) + @classmethod + def init_dictionary(cls): + queryset = cls.objects.filter(status=True, is_value=False) + data = [] + for instance in queryset: + data.append({ + "id": instance.id, + "value": instance.value, + "children": list(cls.objects.filter(parent=instance.id).filter(status=1). + values('label', 'value', 'type', 'color')) + }) + settings.DICTIONARY_CONFIG = {ele.get("value"): ele for ele in data} + print("初始化字典配置完成") + return + + @classmethod + def get_dictionary_label(cls, key, name): + """ + 获取获取字典label值 + :param key: 字典管理中的key + :param name: 对应字典配置的value值 + :return: + """ + children = settings.DICTIONARY_CONFIG.get(key) or [] + for ele in children: + if ele.get("value") == str(name): + return ele.get("label") + return "" + class OperationLog(CoreModel): request_modular = models.CharField(max_length=64, verbose_name="请求模块", null=True, blank=True, help_text="请求模块") @@ -286,7 +316,7 @@ class SystemConfig(CoreModel): key = models.CharField(max_length=20, verbose_name="键", help_text="键", db_index=True) value = models.JSONField(max_length=100, verbose_name="值", help_text="值", null=True, blank=True) sort = models.IntegerField(default=0, verbose_name="排序", help_text="排序", blank=True) - status = models.BooleanField(default=False, verbose_name="启用状态", help_text="启用状态") + status = models.BooleanField(default=True, verbose_name="启用状态", help_text="启用状态") data_options = models.JSONField(verbose_name="数据options", help_text="数据options", null=True, blank=True) FORM_ITEM_TYPE_LIST = ( (0, 'text'), @@ -323,6 +353,57 @@ class SystemConfig(CoreModel): def __str__(self): return f"{self.title}" + def save(self, force_insert=False, force_update=False, using=None, update_fields=None): + super().save(force_insert, force_update, using, update_fields) + self.init_system_config() + + @classmethod + def get_system_config(cls, name): + """ + 1.只传父级的key,返回全部子级,{ "父级key.子级key" : "值" } + 2."父级key.子级key",返回子级值 + + :param name: + :return: + """ + key_list = name.split('.') + if len(key_list) > 2: + return "" + elif len(key_list) == 2: + parent_key = key_list[0] + children_key = key_list[1] + instance = cls.objects.filter(parent__key=parent_key, key=children_key, status=True).first() + return instance.value if instance else "" + elif len(key_list) == 1: + instance = cls.objects.filter(key=key_list[0], status=True, parent_id__isnull=True).first() + if not instance: + return "" + + system_config_obj = cls.objects.filter(parent_id=instance.id, status=True).values( + 'parent__key', 'key', 'value', 'form_item_type').order_by('sort') + data = {} + for system_config in system_config_obj: + data[f"{system_config.get('parent__key')}.{system_config.get('key')}"] = system_config.get( + 'value') or '' + return data + return "" + + @classmethod + def init_system_config(cls): + """ + 初始化系统配置 + :param name: + :return: + """ + data = {} + system_config_obj = SystemConfig.objects.filter(status=True, parent_id__isnull=False).values( + 'parent__key', 'key', 'value', 'form_item_type').order_by('sort') + for system_config in system_config_obj: + data[f"{system_config.get('parent__key')}.{system_config.get('key')}"] = system_config.get('value') or '' + settings.SYSTEM_CONFIG = data + print("初始化系统配置完成") + return + class LoginLog(CoreModel): LOGIN_TYPE_CHOICES = ( diff --git a/backend/dvadmin/system/views/dictionary.py b/backend/dvadmin/system/views/dictionary.py index 9ba0354..9f36ee2 100644 --- a/backend/dvadmin/system/views/dictionary.py +++ b/backend/dvadmin/system/views/dictionary.py @@ -6,7 +6,7 @@ @Created on: 2021/6/3 003 0:30 @Remark: 字典管理 """ -from rest_framework import serializers +from django.conf import settings from rest_framework.views import APIView from dvadmin.system.models import Dictionary @@ -36,26 +36,6 @@ class DictionaryCreateUpdateSerializer(CustomModelSerializer): fields = '__all__' -class DictionaryTreeSerializer(CustomModelSerializer): - """ - 字典表的树形序列化器 - """ - children = serializers.SerializerMethodField(read_only=True) - - def get_children(self, instance): - queryset = Dictionary.objects.filter(parent=instance.id).filter(status=1).values('label', 'value', 'type', - 'color') - if queryset: - return queryset - else: - return [] - - class Meta: - model = Dictionary - fields = ['id', 'value', 'children'] - read_only_fields = ["id"] - - class DictionaryViewSet(CustomModelViewSet): """ 字典管理接口 @@ -83,9 +63,7 @@ class InitDictionaryViewSet(APIView): dictionary_key = self.request.query_params.get('dictionary_key') if dictionary_key: if dictionary_key == 'all': - queryset = self.queryset.filter(status=True, is_value=False) - serializer = DictionaryTreeSerializer(queryset, many=True, request=request) - data = serializer.data + data = [ele for ele in settings.DICTIONARY_CONFIG.values()] else: data = self.queryset.filter(parent__value=dictionary_key, status=True).values('label', 'value', 'type', 'color') diff --git a/backend/dvadmin/system/views/login.py b/backend/dvadmin/system/views/login.py index 553e068..f08a247 100644 --- a/backend/dvadmin/system/views/login.py +++ b/backend/dvadmin/system/views/login.py @@ -14,7 +14,7 @@ from rest_framework.views import APIView from rest_framework_simplejwt.serializers import TokenObtainPairSerializer from rest_framework_simplejwt.views import TokenObtainPairView -from application import settings +from django.conf import settings from dvadmin.system.models import Users from dvadmin.utils.json_response import ErrorResponse, DetailResponse from dvadmin.utils.request_util import save_login_log @@ -34,7 +34,7 @@ class CaptchaView(APIView): ) def get(self, request): data = {} - if settings.CAPTCHA_STATE: + if settings.SYSTEM_CONFIG.get("base.captcha_state"): hashkey = CaptchaStore.generate_key() id = CaptchaStore.objects.filter(hashkey=hashkey).first().id imgage = captcha_image(request, hashkey) @@ -47,15 +47,6 @@ class CaptchaView(APIView): return DetailResponse(data=data) -class CaptchaStatusView(APIView): - - authentication_classes = [] - permission_classes = [] - - def get(self, request): - return DetailResponse(data={"status": settings.CAPTCHA_STATE}) - - class LoginSerializer(TokenObtainPairSerializer): """ 登录的序列化器: @@ -75,7 +66,7 @@ class LoginSerializer(TokenObtainPairSerializer): def validate(self, attrs): captcha = self.initial_data.get("captcha", None) - if settings.CAPTCHA_STATE: + if settings.SYSTEM_CONFIG.get("base.captcha_state"): if captcha is None: raise CustomValidationError("验证码不能为空") self.image_code = CaptchaStore.objects.filter( @@ -87,8 +78,8 @@ class LoginSerializer(TokenObtainPairSerializer): raise CustomValidationError("验证码过期") else: if self.image_code and ( - self.image_code.response == captcha - or self.image_code.challenge == captcha + self.image_code.response == captcha + or self.image_code.challenge == captcha ): self.image_code and self.image_code.delete() else: @@ -171,9 +162,9 @@ class ApiLogin(APIView): username = request.data.get("username") password = request.data.get("password") if user_obj := auth.authenticate( - request, - username=username, - password=hashlib.md5(password.encode(encoding="UTF-8")).hexdigest(), + request, + username=username, + password=hashlib.md5(password.encode(encoding="UTF-8")).hexdigest(), ): login(request, user_obj) return redirect("/") diff --git a/backend/dvadmin/system/views/system_config.py b/backend/dvadmin/system/views/system_config.py index 202f1de..3fc9b6e 100644 --- a/backend/dvadmin/system/views/system_config.py +++ b/backend/dvadmin/system/views/system_config.py @@ -7,12 +7,12 @@ @Remark: 系统配置 """ import django_filters +from django.conf import settings from django.db.models import Q from django_filters.rest_framework import BooleanFilter from rest_framework import serializers from rest_framework.views import APIView -from application import settings from dvadmin.system.models import SystemConfig from dvadmin.utils.json_response import DetailResponse, SuccessResponse, ErrorResponse from dvadmin.utils.models import get_all_models_objects @@ -207,15 +207,4 @@ class InitSettingsViewSet(APIView): permission_classes = [] def get(self, request): - data = { - "site_name": "企业级后台管理系统", # 网站名称 - "site_logo": "", # 网站logo地址 - "login_background": "", # 登录页背景图 - "copyright": "2021-2022 django-vue-admin.com 版权所有", # 版权 - "keep_record": "晋ICP备18005113号-3", # 备案 - "help_url": "https://django-vue-admin.com", # 帮助 - "privacy_url": "#", # 隐私 - "clause_url": "#", # 条款 - "captcha_state": settings.CAPTCHA_STATE, # 验证码 - } - return DetailResponse(data=data) + return DetailResponse(data=settings.SYSTEM_CONFIG)