From 7ee4c3a6726edc10c313a1042a468094638360b6 Mon Sep 17 00:00:00 2001 From: Angelo Date: Fri, 7 Jul 2023 13:37:58 +0800 Subject: [PATCH 1/9] =?UTF-8?q?fix:=20=E6=B6=88=E6=81=AF=E4=B8=AD=E5=BF=83?= =?UTF-8?q?=E6=97=A0=E6=B3=95=E8=8E=B7=E5=8F=96=E9=83=A8=E9=97=A8=E6=95=B0?= =?UTF-8?q?=E6=8D=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web/src/views/system/messageCenter/crud.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/src/views/system/messageCenter/crud.js b/web/src/views/system/messageCenter/crud.js index 115863c..94a56e7 100644 --- a/web/src/views/system/messageCenter/crud.js +++ b/web/src/views/system/messageCenter/crud.js @@ -275,7 +275,7 @@ export const crudOptions = (vm) => { return request({ url: url }).then(ret => { - return ret.data.data + return ret.data }) } }, From acfe3e338dd729a1f081a5eeff2663cfef680a4a Mon Sep 17 00:00:00 2001 From: Angelo Date: Fri, 7 Jul 2023 13:39:21 +0800 Subject: [PATCH 2/9] =?UTF-8?q?fix:=20=E6=94=BE=E8=A1=8C=E6=8C=89=E9=92=AE?= =?UTF-8?q?=E6=9D=83=E9=99=90=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/dvadmin/system/views/menu_button.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/backend/dvadmin/system/views/menu_button.py b/backend/dvadmin/system/views/menu_button.py index 16e0feb..61e64d8 100644 --- a/backend/dvadmin/system/views/menu_button.py +++ b/backend/dvadmin/system/views/menu_button.py @@ -23,7 +23,7 @@ class MenuButtonSerializer(CustomModelSerializer): class Meta: model = MenuButton - fields = ['id', 'name', 'value', 'api', 'method', 'menu'] + fields = ["id", "name", "value", "api", "method", "menu"] read_only_fields = ["id"] @@ -34,7 +34,7 @@ class MenuButtonInitSerializer(CustomModelSerializer): class Meta: model = MenuButton - fields = ['id', 'name', 'value', 'api', 'method', 'menu'] + fields = ["id", "name", "value", "api", "method", "menu"] read_only_fields = ["id"] @@ -58,21 +58,26 @@ class MenuButtonViewSet(CustomModelViewSet): retrieve:单例 destroy:删除 """ + queryset = MenuButton.objects.all() serializer_class = MenuButtonSerializer create_serializer_class = MenuButtonCreateUpdateSerializer update_serializer_class = MenuButtonCreateUpdateSerializer extra_filter_backends = [] - @action(methods=['get'], detail=False) - def get_btn_permission(self,request): + @action(methods=["GET"], detail=False, permission_classes=[]) + def get_btn_permission(self, request): """ 获取当前用户的按钮权限 """ user = request.user if not user.is_superuser: - menuIds = user.role.values_list('menu__id', flat=True) + menuIds = user.role.values_list("menu__id", flat=True) else: menuIds = Menu.objects.filter(status=1) - queryset = MenuButton.objects.filter(menu__in=menuIds).annotate(permission=Concat('menu__web_path',Value(':'),'value',output_field=CharField())).values_list('permission',flat=True) + queryset = ( + MenuButton.objects.filter(menu__in=menuIds) + .annotate(permission=Concat("menu__web_path", Value(":"), "value", output_field=CharField())) + .values_list("permission", flat=True) + ) return DetailResponse(data=queryset) From d308d0ea7b64e5dd088189a6c045e923d2bf4bb4 Mon Sep 17 00:00:00 2001 From: Angelo Date: Fri, 7 Jul 2023 13:40:18 +0800 Subject: [PATCH 3/9] =?UTF-8?q?feat:=20=E5=AE=8C=E5=96=84PermissionDenied?= =?UTF-8?q?=E5=BC=82=E5=B8=B8=E5=93=8D=E5=BA=94=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/dvadmin/utils/exception.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/backend/dvadmin/utils/exception.py b/backend/dvadmin/utils/exception.py index 37adebe..53549c0 100644 --- a/backend/dvadmin/utils/exception.py +++ b/backend/dvadmin/utils/exception.py @@ -11,7 +11,7 @@ import traceback from django.db.models import ProtectedError, RestrictedError from django.http import Http404 -from rest_framework.exceptions import APIException as DRFAPIException, AuthenticationFailed +from rest_framework.exceptions import APIException as DRFAPIException, AuthenticationFailed, PermissionDenied from rest_framework.status import HTTP_407_PROXY_AUTHENTICATION_REQUIRED, HTTP_401_UNAUTHORIZED from rest_framework.views import set_rollback, exception_handler @@ -50,6 +50,8 @@ def CustomExceptionHandler(ex, context): elif isinstance(ex, DRFAPIException): set_rollback() msg = ex.detail + if isinstance(ex, PermissionDenied): + msg = f'{msg} ({context["request"].method}: {context["request"].path})' if isinstance(msg, dict): for k, v in msg.items(): for i in v: From 509d14e72355cc998aa829720f3182e57ec03088 Mon Sep 17 00:00:00 2001 From: Angelo Date: Fri, 7 Jul 2023 19:04:04 +0800 Subject: [PATCH 4/9] =?UTF-8?q?feat:=20LazyLoadFilter=E6=87=92=E5=8A=A0?= =?UTF-8?q?=E8=BD=BD=E8=BF=87=E6=BB=A4=E5=99=A8=E6=89=A9=E5=B1=95=E5=AE=9E?= =?UTF-8?q?=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/dvadmin/system/views/dept.py | 11 ++- backend/dvadmin/utils/filters.py | 107 ++++++++++++++++++--------- web/src/views/system/dept/crud.js | 8 +- 3 files changed, 89 insertions(+), 37 deletions(-) diff --git a/backend/dvadmin/system/views/dept.py b/backend/dvadmin/system/views/dept.py index 7b5a6a1..da9bb61 100644 --- a/backend/dvadmin/system/views/dept.py +++ b/backend/dvadmin/system/views/dept.py @@ -13,6 +13,7 @@ from dvadmin.utils.json_response import DetailResponse, SuccessResponse from dvadmin.utils.permission import AnonymousUserPermission from dvadmin.utils.serializers import CustomModelSerializer from dvadmin.utils.viewset import CustomModelViewSet +from dvadmin.utils.filters import LazyLoadFilter class DeptSerializer(CustomModelSerializer): @@ -120,6 +121,12 @@ class DeptCreateUpdateSerializer(CustomModelSerializer): fields = '__all__' +class DeptLazyFilter(LazyLoadFilter): + class Meta: + model = Dept + fields = ['name', 'parent', 'status'] + + class DeptViewSet(CustomModelViewSet): """ 部门管理接口 @@ -129,11 +136,13 @@ class DeptViewSet(CustomModelViewSet): retrieve:单例 destroy:删除 """ + queryset = Dept.objects.all() serializer_class = DeptSerializer create_serializer_class = DeptCreateUpdateSerializer update_serializer_class = DeptCreateUpdateSerializer - filter_fields = ['name', 'id', 'parent'] + # filter_fields = ["name", "id", "parent"] + filter_class = DeptLazyFilter search_fields = [] # extra_filter_backends = [] import_serializer_class = DeptImportSerializer diff --git a/backend/dvadmin/utils/filters.py b/backend/dvadmin/utils/filters.py index ebb4cb5..24d6d4c 100644 --- a/backend/dvadmin/utils/filters.py +++ b/backend/dvadmin/utils/filters.py @@ -12,6 +12,7 @@ from collections import OrderedDict from functools import reduce import six +from django import forms from django.db import models from django.db.models import Q, F from django.db.models.constants import LOOKUP_SEP @@ -19,6 +20,7 @@ from django_filters import utils from django_filters.conf import settings from django_filters.constants import ALL_FIELDS from django_filters.filters import CharFilter +from django_filters.filterset import FilterSet, FilterSetMetaclass from django_filters.rest_framework import DjangoFilterBackend from django_filters.utils import get_model_field from rest_framework.filters import BaseFilterBackend @@ -71,9 +73,7 @@ class DataLevelPermissionsFilter(BaseFilterBackend): permission__api=F("url"), permission__method=F("method") ) api_white_list = [ - str(item.get("permission__api").replace("{id}", ".*?")) - + ":" - + str(item.get("permission__method")) + str(item.get("permission__api").replace("{id}", ".*?")) + ":" + str(item.get("permission__method")) for item in api_white_list if item.get("permission__api") ] @@ -119,19 +119,13 @@ class DataLevelPermissionsFilter(BaseFilterBackend): # 4. 只为仅本人数据权限时只返回过滤本人数据,并且部门为自己本部门(考虑到用户会变部门,只能看当前用户所在的部门数据) if 0 in dataScope_list: - return queryset.filter( - creator=request.user, dept_belong_id=user_dept_id - ) + return queryset.filter(creator=request.user, dept_belong_id=user_dept_id) # 5. 自定数据权限 获取部门,根据部门过滤 dept_list = [] for ele in dataScope_list: if ele == 4: - dept_list.extend( - request.user.role.filter(status=1).values_list( - "dept__id", flat=True - ) - ) + dept_list.extend(request.user.role.filter(status=1).values_list("dept__id", flat=True)) elif ele == 2: dept_list.append(user_dept_id) elif ele == 1: @@ -141,7 +135,7 @@ class DataLevelPermissionsFilter(BaseFilterBackend): user_dept_id, ) ) - if queryset.model._meta.model_name == 'dept': + if queryset.model._meta.model_name == "dept": return queryset.filter(id__in=list(set(dept_list))) return queryset.filter(dept_belong_id__in=list(set(dept_list))) else: @@ -186,16 +180,14 @@ class CustomDjangoFilterBackend(DjangoFilterBackend): # TODO: remove assertion in 2.1 if filterset_class is None and hasattr(view, "filter_class"): utils.deprecate( - "`%s.filter_class` attribute should be renamed `filterset_class`." - % view.__class__.__name__ + "`%s.filter_class` attribute should be renamed `filterset_class`." % view.__class__.__name__ ) filterset_class = getattr(view, "filter_class", None) # TODO: remove assertion in 2.1 if filterset_fields is None and hasattr(view, "filter_fields"): utils.deprecate( - "`%s.filter_fields` attribute should be renamed `filterset_fields`." - % view.__class__.__name__ + "`%s.filter_fields` attribute should be renamed `filterset_fields`." % view.__class__.__name__ ) filterset_fields = getattr(view, "filter_fields", None) @@ -224,8 +216,9 @@ class CustomDjangoFilterBackend(DjangoFilterBackend): return [ f.name for f in sorted(opts.fields + opts.many_to_many) - if (f.name == 'id') or not isinstance(f, models.AutoField) - and not (getattr(f.remote_field, "parent_link", False)) + if (f.name == "id") + or not isinstance(f, models.AutoField) + and not (getattr(f.remote_field, "parent_link", False)) ] @classmethod @@ -239,9 +232,9 @@ class CustomDjangoFilterBackend(DjangoFilterBackend): exclude = cls._meta.exclude assert not (fields is None and exclude is None), ( - "Setting 'Meta.model' without either 'Meta.fields' or 'Meta.exclude' " - "has been deprecated since 0.15.0 and is now disallowed. Add an explicit " - "'Meta.fields' or 'Meta.exclude' to the %s class." % cls.__name__ + "Setting 'Meta.model' without either 'Meta.fields' or 'Meta.exclude' " + "has been deprecated since 0.15.0 and is now disallowed. Add an explicit " + "'Meta.fields' or 'Meta.exclude' to the %s class." % cls.__name__ ) # Setting exclude with no fields implies all other fields. @@ -255,9 +248,7 @@ class CustomDjangoFilterBackend(DjangoFilterBackend): # Remove excluded fields exclude = exclude or [] if not isinstance(fields, dict): - fields = [ - (f, [settings.DEFAULT_LOOKUP_EXPR]) for f in fields if f not in exclude - ] + fields = [(f, [settings.DEFAULT_LOOKUP_EXPR]) for f in fields if f not in exclude] else: fields = [(f, lookups) for f, lookups in fields.items() if f not in exclude] @@ -291,9 +282,12 @@ class CustomDjangoFilterBackend(DjangoFilterBackend): if field is None: undefined.append(field_name) # 更新默认字符串搜索为模糊搜索 - if isinstance(field, (models.CharField)) and filterset_fields == '__all__' and lookups == [ - 'exact']: - lookups = ['icontains'] + if ( + isinstance(field, (models.CharField)) + and filterset_fields == "__all__" + and lookups == ["exact"] + ): + lookups = ["icontains"] for lookup_expr in lookups: filter_name = cls.get_filter_name(field_name, lookup_expr) @@ -303,20 +297,15 @@ class CustomDjangoFilterBackend(DjangoFilterBackend): continue if field is not None: - filters[filter_name] = cls.filter_for_field( - field, field_name, lookup_expr - ) + filters[filter_name] = cls.filter_for_field(field, field_name, lookup_expr) # Allow Meta.fields to contain declared filters *only* when a list/tuple if isinstance(cls._meta.fields, (list, tuple)): - undefined = [ - f for f in undefined if f not in cls.declared_filters - ] + undefined = [f for f in undefined if f not in cls.declared_filters] if undefined: raise TypeError( - "'Meta.fields' must not contain non-model field names: %s" - % ", ".join(undefined) + "'Meta.fields' must not contain non-model field names: %s" % ", ".join(undefined) ) # Add in declared filters. This is necessary since we don't enforce adding @@ -364,3 +353,51 @@ class CustomDjangoFilterBackend(DjangoFilterBackend): if not filterset.is_valid() and self.raise_exception: raise utils.translate_validation(filterset.errors) return filterset.qs + + +# ####################### 懒加载FilterSet ####################### # + + +class FilterSetOptions: + def __init__(self, options=None): + self.model = getattr(options, "model", None) + self.fields = getattr(options, "fields", None) + self.exclude = getattr(options, "exclude", None) + + # CharField默认模糊查询 + self.filter_overrides = getattr( + options, + "filter_overrides", + { + models.CharField: { + "filter_class": CharFilter, + "extra": lambda f: { + "lookup_expr": "icontains", + }, + } + }, + ) + + self.form = getattr(options, "form", forms.Form) + + +class LazyLoadFilterSetMetaclass(FilterSetMetaclass): + def __new__(cls, name, bases, attrs): + attrs["declared_filters"] = cls.get_declared_filters(bases, attrs) + + new_class = super().__new__(cls, name, bases, attrs) + new_class._meta = FilterSetOptions(getattr(new_class, "Meta", None)) + new_class.base_filters = new_class.get_filters() + + return new_class + + +class LazyLoadFilter(FilterSet, metaclass=LazyLoadFilterSetMetaclass): + @property + def qs(self): + is_node = self.queryset.filter(parent__isnull=False).exists() + if not is_node: + self.queryset = self.queryset.model.objects.filter(parent__in=self.queryset) + parent_ids = set(super().qs.values_list("parent_id", flat=True)) + return self.queryset.model.objects.filter(id__in=parent_ids) + return super().qs diff --git a/web/src/views/system/dept/crud.js b/web/src/views/system/dept/crud.js index ab6311f..2fe3247 100644 --- a/web/src/views/system/dept/crud.js +++ b/web/src/views/system/dept/crud.js @@ -20,7 +20,13 @@ export const crudOptions = (vm) => { hasChild: 'hasChild', lazy: true, loadMethod: ({ row }) => { - return api.GetList({ parent: row.id }).then(ret => { + let query = JSON.parse(JSON.stringify(vm.getSearch().getForm())) + query = Object.fromEntries( + Object.entries(query).filter(([_, value]) => ![undefined, null, [], '[]', ''].includes(value)) + ) + query.parent = row.id + // console.log(query) + return api.GetList({ ...query }).then(ret => { return ret.data.data }) }, From 6c9326c63c83693bd6a49aceeebc45428d7745a6 Mon Sep 17 00:00:00 2001 From: Angelo Date: Fri, 7 Jul 2023 19:24:52 +0800 Subject: [PATCH 5/9] =?UTF-8?q?fix:=20=E7=A6=81=E7=94=A8=E9=83=A8=E9=97=A8?= =?UTF-8?q?=E7=AE=A1=E7=90=86=E5=85=B3=E9=94=AE=E8=AF=8D=E6=9F=A5=E8=AF=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web/src/views/system/dept/crud.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/src/views/system/dept/crud.js b/web/src/views/system/dept/crud.js index 2fe3247..328842b 100644 --- a/web/src/views/system/dept/crud.js +++ b/web/src/views/system/dept/crud.js @@ -77,7 +77,7 @@ export const crudOptions = (vm) => { show: false, disabled: true, search: { - disabled: false + disabled: true }, form: { disabled: true, From 695df6bf6c90d2edff8b68683c644c69042bedf2 Mon Sep 17 00:00:00 2001 From: Angelo Date: Fri, 7 Jul 2023 21:03:19 +0800 Subject: [PATCH 6/9] =?UTF-8?q?feat:=20=E9=83=A8=E9=97=A8=E5=90=8D?= =?UTF-8?q?=E7=A7=B0=E5=8D=95=E8=A1=8C=E5=B1=95=E7=A4=BA(tooltip)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/dvadmin/utils/filters.py | 2 ++ web/src/views/system/dept/crud.js | 1 + 2 files changed, 3 insertions(+) diff --git a/backend/dvadmin/utils/filters.py b/backend/dvadmin/utils/filters.py index 24d6d4c..2de1115 100644 --- a/backend/dvadmin/utils/filters.py +++ b/backend/dvadmin/utils/filters.py @@ -396,8 +396,10 @@ class LazyLoadFilter(FilterSet, metaclass=LazyLoadFilterSetMetaclass): @property def qs(self): is_node = self.queryset.filter(parent__isnull=False).exists() + # print(is_node, self.queryset) if not is_node: self.queryset = self.queryset.model.objects.filter(parent__in=self.queryset) parent_ids = set(super().qs.values_list("parent_id", flat=True)) + # print(self.queryset, parent_ids, super().qs) return self.queryset.model.objects.filter(id__in=parent_ids) return super().qs diff --git a/web/src/views/system/dept/crud.js b/web/src/views/system/dept/crud.js index 328842b..a910d1d 100644 --- a/web/src/views/system/dept/crud.js +++ b/web/src/views/system/dept/crud.js @@ -144,6 +144,7 @@ export const crudOptions = (vm) => { }, width: 180, type: 'input', + showOverflow: 'tooltip', form: { rules: [ // 表单校验规则 From 0c301ef3a70085c59bd94901b4880aafac847e73 Mon Sep 17 00:00:00 2001 From: Angelo Date: Sat, 8 Jul 2023 14:53:58 +0800 Subject: [PATCH 7/9] =?UTF-8?q?refactor:=20=E9=87=8D=E6=9E=84LazyLoadFilte?= =?UTF-8?q?r?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/dvadmin/system/models.py | 1 + backend/dvadmin/utils/filters.py | 89 +++++++++++++++++++++++++++++--- 2 files changed, 83 insertions(+), 7 deletions(-) diff --git a/backend/dvadmin/system/models.py b/backend/dvadmin/system/models.py index 4141c57..6e9101a 100644 --- a/backend/dvadmin/system/models.py +++ b/backend/dvadmin/system/models.py @@ -131,6 +131,7 @@ class Dept(CoreModel): null=True, blank=True, help_text="上级部门", + db_index=True ) @classmethod diff --git a/backend/dvadmin/utils/filters.py b/backend/dvadmin/utils/filters.py index 2de1115..10a15a2 100644 --- a/backend/dvadmin/utils/filters.py +++ b/backend/dvadmin/utils/filters.py @@ -357,6 +357,68 @@ class CustomDjangoFilterBackend(DjangoFilterBackend): # ####################### 懒加载FilterSet ####################### # +import time + + +def calculate_execution_time(func): + def wrapper(*args, **kwargs): + start_time = time.time() + result = func(*args, **kwargs) + end_time = time.time() + execution_time = end_time - start_time + print(f"Function {func.__name__} took {execution_time:.6f} seconds to execute.", flush=True) + return result + + return wrapper + + +def get_children(model: models, obj_id: int, all_qs=None, rec_list=None): + if not all_qs: + all_qs = model.objects.all().values("id", "parent") + if rec_list is None: + rec_list = [obj_id] + for ele in all_qs: + if ele.get("parent") == obj_id: + rec_list.append(ele.get("id")) + get_dept(ele.get("id"), all_qs, rec_list) + return list(set(rec_list)) + + +@calculate_execution_time +def get_qs_children(model, qs): + dept_ids = [] + for d in qs: + r = get_children(model, d.id) + dept_ids.extend(r) + return list(set(dept_ids)) + + +@calculate_execution_time +def next_layer_data(qs_filter, qs_node): + print(f"过滤查询集 ==> {qs_filter}", flush=True) + print(f"当前传入的待渲染节点 ==> {qs_node}", flush=True) + + parent_nodes = set(qs_node.values_list("id", flat=True)) + print(f"待渲染节点的id ==> {parent_nodes=}", flush=True) + if set(qs_filter) == set(qs_node): + return parent_nodes + + # qs_filter内所有父级id 去重 + parent_ids = set() + for node in qs_filter: + while node.parent: + if node.id in parent_nodes: + parent_ids.add(node.id) + break + if node.parent.id in parent_nodes: + parent_ids.add(node.parent.id) + break + node = node.parent + # parent_ids.add(node.id) + print(f"过滤查询集的父节点id ==> {parent_ids=}", flush=True) + + return parent_ids + class FilterSetOptions: def __init__(self, options=None): @@ -395,11 +457,24 @@ class LazyLoadFilterSetMetaclass(FilterSetMetaclass): class LazyLoadFilter(FilterSet, metaclass=LazyLoadFilterSetMetaclass): @property def qs(self): - is_node = self.queryset.filter(parent__isnull=False).exists() - # print(is_node, self.queryset) - if not is_node: - self.queryset = self.queryset.model.objects.filter(parent__in=self.queryset) - parent_ids = set(super().qs.values_list("parent_id", flat=True)) - # print(self.queryset, parent_ids, super().qs) - return self.queryset.model.objects.filter(id__in=parent_ids) + queryset = self.queryset + filter_params = [k for k, v in self.form.cleaned_data.items() if not v] + for field in filter_params: + self.form.cleaned_data.pop(field) + self.form.cleaned_data.pop("parent", None) + print(queryset, flush=True) + if self.form.cleaned_data: + all_dept = queryset.count() == queryset.model.objects.all().count() + p_set = set(queryset.values_list("parent", flat=True)) + all_root = len(p_set) == 1 and p_set.pop() is None + is_root = all_dept or all_root + ids = ( + list(set(queryset.model.objects.all().values_list("id", flat=True))) + if is_root + else get_qs_children(queryset.model, queryset) + ) + # print(f"{ids=}", flush=True) + self.queryset = queryset.model.objects.filter(id__in=ids) + node_ids = next_layer_data(super().qs, queryset) + return queryset.model.objects.filter(id__in=node_ids) return super().qs From 554f3e1dc8e5ddf45d5125bc393432050b5d5661 Mon Sep 17 00:00:00 2001 From: Angelo Date: Sat, 8 Jul 2023 16:03:47 +0800 Subject: [PATCH 8/9] =?UTF-8?q?refactor:=20=E4=BC=98=E5=8C=96=E6=9F=A5?= =?UTF-8?q?=E8=AF=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/dvadmin/utils/filters.py | 59 ++++++++++++-------------------- 1 file changed, 22 insertions(+), 37 deletions(-) diff --git a/backend/dvadmin/utils/filters.py b/backend/dvadmin/utils/filters.py index 10a15a2..a17e21f 100644 --- a/backend/dvadmin/utils/filters.py +++ b/backend/dvadmin/utils/filters.py @@ -372,37 +372,33 @@ def calculate_execution_time(func): return wrapper -def get_children(model: models, obj_id: int, all_qs=None, rec_list=None): - if not all_qs: - all_qs = model.objects.all().values("id", "parent") - if rec_list is None: - rec_list = [obj_id] - for ele in all_qs: - if ele.get("parent") == obj_id: - rec_list.append(ele.get("id")) - get_dept(ele.get("id"), all_qs, rec_list) - return list(set(rec_list)) +# def get_children(model: models, obj_id: int, all_qs=None, rec_list=None): +# if not all_qs: +# all_qs = model.objects.all().values("id", "parent") +# if rec_list is None: +# rec_list = [obj_id] +# for ele in all_qs: +# if ele.get("parent") == obj_id: +# rec_list.append(ele.get("id")) +# get_dept(ele.get("id"), all_qs, rec_list) +# return list(set(rec_list)) -@calculate_execution_time -def get_qs_children(model, qs): - dept_ids = [] - for d in qs: - r = get_children(model, d.id) - dept_ids.extend(r) - return list(set(dept_ids)) +# @calculate_execution_time +# def get_qs_children(model, qs): +# dept_ids = [] +# for d in qs: +# r = get_children(model, d.id) +# dept_ids.extend(r) +# return list(set(dept_ids)) -@calculate_execution_time def next_layer_data(qs_filter, qs_node): - print(f"过滤查询集 ==> {qs_filter}", flush=True) - print(f"当前传入的待渲染节点 ==> {qs_node}", flush=True) - parent_nodes = set(qs_node.values_list("id", flat=True)) - print(f"待渲染节点的id ==> {parent_nodes=}", flush=True) + # print(f"过滤查询集 ==> {qs_filter}", flush=True) + # print(f"待渲染节点的id ==> {parent_nodes=}", flush=True) if set(qs_filter) == set(qs_node): return parent_nodes - # qs_filter内所有父级id 去重 parent_ids = set() for node in qs_filter: @@ -414,9 +410,7 @@ def next_layer_data(qs_filter, qs_node): parent_ids.add(node.parent.id) break node = node.parent - # parent_ids.add(node.id) - print(f"过滤查询集的父节点id ==> {parent_ids=}", flush=True) - + # print(f"过滤查询集的父节点id ==> {parent_ids=}", flush=True) return parent_ids @@ -455,6 +449,7 @@ class LazyLoadFilterSetMetaclass(FilterSetMetaclass): class LazyLoadFilter(FilterSet, metaclass=LazyLoadFilterSetMetaclass): + # @calculate_execution_time @property def qs(self): queryset = self.queryset @@ -464,17 +459,7 @@ class LazyLoadFilter(FilterSet, metaclass=LazyLoadFilterSetMetaclass): self.form.cleaned_data.pop("parent", None) print(queryset, flush=True) if self.form.cleaned_data: - all_dept = queryset.count() == queryset.model.objects.all().count() - p_set = set(queryset.values_list("parent", flat=True)) - all_root = len(p_set) == 1 and p_set.pop() is None - is_root = all_dept or all_root - ids = ( - list(set(queryset.model.objects.all().values_list("id", flat=True))) - if is_root - else get_qs_children(queryset.model, queryset) - ) - # print(f"{ids=}", flush=True) - self.queryset = queryset.model.objects.filter(id__in=ids) + self.queryset = queryset.model.objects.all() node_ids = next_layer_data(super().qs, queryset) return queryset.model.objects.filter(id__in=node_ids) return super().qs From b6dd7adf99bc35c1f96e42358fd287dae77d8b83 Mon Sep 17 00:00:00 2001 From: Angelo Date: Sat, 8 Jul 2023 16:21:10 +0800 Subject: [PATCH 9/9] feat: dept table resizable --- backend/dvadmin/utils/filters.py | 2 +- web/src/views/system/dept/crud.js | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/backend/dvadmin/utils/filters.py b/backend/dvadmin/utils/filters.py index a17e21f..52de84a 100644 --- a/backend/dvadmin/utils/filters.py +++ b/backend/dvadmin/utils/filters.py @@ -457,7 +457,7 @@ class LazyLoadFilter(FilterSet, metaclass=LazyLoadFilterSetMetaclass): for field in filter_params: self.form.cleaned_data.pop(field) self.form.cleaned_data.pop("parent", None) - print(queryset, flush=True) + # print(queryset, flush=True) if self.form.cleaned_data: self.queryset = queryset.model.objects.all() node_ids = next_layer_data(super().qs, queryset) diff --git a/web/src/views/system/dept/crud.js b/web/src/views/system/dept/crud.js index a910d1d..a397850 100644 --- a/web/src/views/system/dept/crud.js +++ b/web/src/views/system/dept/crud.js @@ -13,6 +13,7 @@ export const crudOptions = (vm) => { height: '100%', // 表格高度100%, 使用toolbar必须设置 highlightCurrentRow: false, defaultExpandAll: true, + resizable: true, treeConfig: { transform: true, rowField: 'id', @@ -34,6 +35,7 @@ export const crudOptions = (vm) => { } }, rowHandle: { + fixed: 'right', width: 140, view: { thin: true, @@ -61,7 +63,7 @@ export const crudOptions = (vm) => { // 或者直接传true,不显示title,不居中 title: '序号', align: 'center', - width: 100 + width: 70 }, viewOptions: { @@ -142,7 +144,6 @@ export const crudOptions = (vm) => { } } }, - width: 180, type: 'input', showOverflow: 'tooltip', form: {