diff --git a/backend/dvadmin/system/models.py b/backend/dvadmin/system/models.py index ebdaaca..7a71c67 100644 --- a/backend/dvadmin/system/models.py +++ b/backend/dvadmin/system/models.py @@ -74,6 +74,14 @@ class Users(CoreModel, AbstractUser): blank=True, help_text="关联部门", ) + manage_dept = models.ManyToManyField( + to="Dept", + verbose_name="管理部门", + db_constraint=False, + blank=True, + help_text="管理部门", + related_name='manage_dept_set' + ) login_error_count = models.IntegerField(default=0, verbose_name="登录错误次数", help_text="登录错误次数") pwd_change_count = models.IntegerField(default=0,blank=True, verbose_name="密码修改次数", help_text="密码修改次数") objects = CustomUserManager() diff --git a/backend/dvadmin/system/views/user.py b/backend/dvadmin/system/views/user.py index c31540c..4e09f90 100644 --- a/backend/dvadmin/system/views/user.py +++ b/backend/dvadmin/system/views/user.py @@ -90,6 +90,8 @@ class UserCreateSerializer(CustomModelSerializer): data = super().save(**kwargs) data.dept_belong_id = data.dept_id data.save() + if not self.validated_data.get('manage_dept', None): + data.manage_dept.add(data.dept_id) data.post.set(self.initial_data.get("post", [])) return data @@ -127,6 +129,8 @@ class UserUpdateSerializer(CustomModelSerializer): data = super().save(**kwargs) data.dept_belong_id = data.dept_id data.save() + if not self.validated_data.get('manage_dept', None): + data.manage_dept.add(data.dept_id) data.post.set(self.initial_data.get("post", [])) return data @@ -426,12 +430,9 @@ class UserViewSet(CustomModelViewSet): queryset = self.filter_queryset(self.get_queryset()) else: queryset = self.filter_queryset(self.get_queryset()) - # print(queryset.values('id','name','dept__id')) page = self.paginate_queryset(queryset) if page is not None: serializer = self.get_serializer(page, many=True, request=request) - # print(serializer.data) return self.get_paginated_response(serializer.data) serializer = self.get_serializer(queryset, many=True, request=request) - return SuccessResponse(data=serializer.data, msg="获取成功") diff --git a/backend/dvadmin/utils/filters.py b/backend/dvadmin/utils/filters.py index f61fc62..9b98edc 100644 --- a/backend/dvadmin/utils/filters.py +++ b/backend/dvadmin/utils/filters.py @@ -15,15 +15,16 @@ import six from django.db import models from django.db.models import Q, F from django.db.models.constants import LOOKUP_SEP -from django_filters import utils, FilterSet from django_filters.constants import ALL_FIELDS -from django_filters.filters import CharFilter, DateTimeFromToRangeFilter from django_filters.rest_framework import DjangoFilterBackend -from django_filters.utils import get_model_field +from django_filters.utils import get_model_field, translate_validation, deprecate +from rest_framework.request import Request from rest_framework.filters import BaseFilterBackend from django_filters.conf import settings -from dvadmin.system.models import Dept, ApiWhiteList, RoleMenuButtonPermission, MenuButton -from dvadmin.utils.models import CoreModel + +from dvadmin.system.models import Dept, ApiWhiteList, RoleMenuButtonPermission, MenuButton, Users +from util.currency import recursion_down_fast + class CoreModelFilterBankend(BaseFilterBackend): """ @@ -200,6 +201,31 @@ class DataLevelPermissionsFilter(BaseFilterBackend): return queryset.filter(dept_belong_id__in=list(set(dept_list))) +class DataLevelPermissionsSubFilter(DataLevelPermissionsFilter): + """数据级权限过滤的子过滤器,过滤管理部门字段manage_dept""" + + def _extracted_from_filter_queryset_33(self, request:Request, queryset, api, method): + u:Users = request.user + manage_depts = u.manage_dept.all() + if not manage_depts: + return queryset + dept_list = [] + for dept in manage_depts: + dept_list.extend(recursion_down_fast(dept, 'parent', 'id')) + # 自己创建的数据要能看到 + # 应对归属a管b、c等情况,如果自己创建数据则是a,不显式指定自己的数据就查不到 + if queryset.model._meta.model_name == 'dept': + return queryset.filter(Q(id__in=set(dept_list)) | Q(creator=u)) + return queryset.filter(Q(dept_belong_id__in=set(dept_list)) | + Q(creator=u)) + + +class DataLevelPermissionMargeFilter(DataLevelPermissionsFilter): + def _extracted_from_filter_queryset_33(self, request, queryset, api, method): + queryset = super()._extracted_from_filter_queryset_33(request, queryset, api, method) + return DataLevelPermissionsSubFilter._extracted_from_filter_queryset_33(self, request, queryset, api, method) + + class CustomDjangoFilterBackend(DjangoFilterBackend): lookup_prefixes = { "^": "istartswith", @@ -240,14 +266,14 @@ class CustomDjangoFilterBackend(DjangoFilterBackend): # TODO: remove assertion in 2.1 if filterset_class is None and hasattr(view, "filter_class"): - utils.deprecate( + deprecate( "`%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( + deprecate( "`%s.filter_fields` attribute should be renamed `filterset_fields`." % view.__class__.__name__ ) self.filter_fields = getattr(view, "filter_fields", None) @@ -427,5 +453,5 @@ class CustomDjangoFilterBackend(DjangoFilterBackend): return queryset if not filterset.is_valid() and self.raise_exception: - raise utils.translate_validation(filterset.errors) + raise translate_validation(filterset.errors) return filterset.qs diff --git a/backend/dvadmin/utils/viewset.py b/backend/dvadmin/utils/viewset.py index 89de67a..43160e6 100644 --- a/backend/dvadmin/utils/viewset.py +++ b/backend/dvadmin/utils/viewset.py @@ -16,7 +16,7 @@ from drf_yasg.utils import swagger_auto_schema from rest_framework.decorators import action from rest_framework.viewsets import ModelViewSet -from dvadmin.utils.filters import DataLevelPermissionsFilter, CoreModelFilterBankend +from dvadmin.utils.filters import CoreModelFilterBankend, DataLevelPermissionMargeFilter from dvadmin.utils.import_export_mixin import ExportSerializerMixin, ImportSerializerMixin from dvadmin.utils.json_response import SuccessResponse, ErrorResponse, DetailResponse from dvadmin.utils.permission import CustomPermission @@ -41,7 +41,7 @@ class CustomModelViewSet(ModelViewSet, ImportSerializerMixin, ExportSerializerMi update_serializer_class = None filter_fields = '__all__' search_fields = () - extra_filter_class = [CoreModelFilterBankend,DataLevelPermissionsFilter] + extra_filter_class = [CoreModelFilterBankend,DataLevelPermissionMargeFilter] permission_classes = [CustomPermission] import_field_dict = {} export_field_label = {} diff --git a/web/src/views/system/user/crud.tsx b/web/src/views/system/user/crud.tsx index d5c1696..30515d9 100644 --- a/web/src/views/system/user/crud.tsx +++ b/web/src/views/system/user/crud.tsx @@ -205,10 +205,7 @@ export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProp }, }, dept: { - title: '部门', - search: { - disabled: true, - }, + title: '所属部门', type: 'dict-tree', dict: dict({ isTree: true, @@ -217,7 +214,7 @@ export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProp label: 'name' }), column: { - minWidth: 200, //最小列宽 + minWidth: 300, //最小列宽 formatter({ value, row, index }) { return row.dept_name_all } @@ -243,6 +240,39 @@ export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProp }, }, }, + manage_dept: { + title: '管理部门', + type: 'dict-tree', + dict: dict({ + isTree: true, + url: '/api/system/dept/all_dept/', + value: 'id', + label: 'name' + }), + column: { + minWidth: 300 + }, + form: { + value: [], + component: { + filterable: true, + multiple: true, + placeholder: '请选择', + clearable: true, + collapseTags: true, + maxCollapseTags: 2, + collapseTagsTooltip: true, + props: { + checkStrictly: true, + props: { + value: 'id', + label: 'name', + }, + }, + }, + helper: '不选则默认为所属部门', + }, + }, role: { title: '角色', search: { @@ -378,6 +408,9 @@ export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProp dict: dict({ data: dictionary('button_status_bool'), }), + form: { + value: true + } }, avatar: { title: '头像', @@ -392,8 +425,8 @@ export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProp }, ...commonCrudConfig({ dept_belong_id: { - form: true, - table: true + form: false, + table: false } }) },