用户的管理部门权限功能

This commit is contained in:
ahui
2025-08-14 10:35:51 +08:00
parent 2a9f5be895
commit 6e9b94aed2
5 changed files with 88 additions and 20 deletions

View File

@@ -74,6 +74,14 @@ class Users(CoreModel, AbstractUser):
blank=True, blank=True,
help_text="关联部门", 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="登录错误次数") login_error_count = models.IntegerField(default=0, verbose_name="登录错误次数", help_text="登录错误次数")
pwd_change_count = models.IntegerField(default=0,blank=True, verbose_name="密码修改次数", help_text="密码修改次数") pwd_change_count = models.IntegerField(default=0,blank=True, verbose_name="密码修改次数", help_text="密码修改次数")
objects = CustomUserManager() objects = CustomUserManager()

View File

@@ -90,6 +90,8 @@ class UserCreateSerializer(CustomModelSerializer):
data = super().save(**kwargs) data = super().save(**kwargs)
data.dept_belong_id = data.dept_id data.dept_belong_id = data.dept_id
data.save() 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", [])) data.post.set(self.initial_data.get("post", []))
return data return data
@@ -127,6 +129,8 @@ class UserUpdateSerializer(CustomModelSerializer):
data = super().save(**kwargs) data = super().save(**kwargs)
data.dept_belong_id = data.dept_id data.dept_belong_id = data.dept_id
data.save() 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", [])) data.post.set(self.initial_data.get("post", []))
return data return data
@@ -426,12 +430,9 @@ class UserViewSet(CustomModelViewSet):
queryset = self.filter_queryset(self.get_queryset()) queryset = self.filter_queryset(self.get_queryset())
else: else:
queryset = self.filter_queryset(self.get_queryset()) queryset = self.filter_queryset(self.get_queryset())
# print(queryset.values('id','name','dept__id'))
page = self.paginate_queryset(queryset) page = self.paginate_queryset(queryset)
if page is not None: if page is not None:
serializer = self.get_serializer(page, many=True, request=request) serializer = self.get_serializer(page, many=True, request=request)
# print(serializer.data)
return self.get_paginated_response(serializer.data) return self.get_paginated_response(serializer.data)
serializer = self.get_serializer(queryset, many=True, request=request) serializer = self.get_serializer(queryset, many=True, request=request)
return SuccessResponse(data=serializer.data, msg="获取成功") return SuccessResponse(data=serializer.data, msg="获取成功")

View File

@@ -15,15 +15,16 @@ import six
from django.db import models from django.db import models
from django.db.models import Q, F from django.db.models import Q, F
from django.db.models.constants import LOOKUP_SEP from django.db.models.constants import LOOKUP_SEP
from django_filters import utils, FilterSet
from django_filters.constants import ALL_FIELDS from django_filters.constants import ALL_FIELDS
from django_filters.filters import CharFilter, DateTimeFromToRangeFilter
from django_filters.rest_framework import DjangoFilterBackend 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 rest_framework.filters import BaseFilterBackend
from django_filters.conf import settings 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): class CoreModelFilterBankend(BaseFilterBackend):
""" """
@@ -200,6 +201,31 @@ class DataLevelPermissionsFilter(BaseFilterBackend):
return queryset.filter(dept_belong_id__in=list(set(dept_list))) 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): class CustomDjangoFilterBackend(DjangoFilterBackend):
lookup_prefixes = { lookup_prefixes = {
"^": "istartswith", "^": "istartswith",
@@ -240,14 +266,14 @@ class CustomDjangoFilterBackend(DjangoFilterBackend):
# TODO: remove assertion in 2.1 # TODO: remove assertion in 2.1
if filterset_class is None and hasattr(view, "filter_class"): 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__ "`%s.filter_class` attribute should be renamed `filterset_class`." % view.__class__.__name__
) )
filterset_class = getattr(view, "filter_class", None) filterset_class = getattr(view, "filter_class", None)
# TODO: remove assertion in 2.1 # TODO: remove assertion in 2.1
if filterset_fields is None and hasattr(view, "filter_fields"): 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__ "`%s.filter_fields` attribute should be renamed `filterset_fields`." % view.__class__.__name__
) )
self.filter_fields = getattr(view, "filter_fields", None) self.filter_fields = getattr(view, "filter_fields", None)
@@ -427,5 +453,5 @@ class CustomDjangoFilterBackend(DjangoFilterBackend):
return queryset return queryset
if not filterset.is_valid() and self.raise_exception: if not filterset.is_valid() and self.raise_exception:
raise utils.translate_validation(filterset.errors) raise translate_validation(filterset.errors)
return filterset.qs return filterset.qs

View File

@@ -16,7 +16,7 @@ from drf_yasg.utils import swagger_auto_schema
from rest_framework.decorators import action from rest_framework.decorators import action
from rest_framework.viewsets import ModelViewSet 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.import_export_mixin import ExportSerializerMixin, ImportSerializerMixin
from dvadmin.utils.json_response import SuccessResponse, ErrorResponse, DetailResponse from dvadmin.utils.json_response import SuccessResponse, ErrorResponse, DetailResponse
from dvadmin.utils.permission import CustomPermission from dvadmin.utils.permission import CustomPermission
@@ -41,7 +41,7 @@ class CustomModelViewSet(ModelViewSet, ImportSerializerMixin, ExportSerializerMi
update_serializer_class = None update_serializer_class = None
filter_fields = '__all__' filter_fields = '__all__'
search_fields = () search_fields = ()
extra_filter_class = [CoreModelFilterBankend,DataLevelPermissionsFilter] extra_filter_class = [CoreModelFilterBankend,DataLevelPermissionMargeFilter]
permission_classes = [CustomPermission] permission_classes = [CustomPermission]
import_field_dict = {} import_field_dict = {}
export_field_label = {} export_field_label = {}

View File

@@ -205,10 +205,7 @@ export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProp
}, },
}, },
dept: { dept: {
title: '部门', title: '所属部门',
search: {
disabled: true,
},
type: 'dict-tree', type: 'dict-tree',
dict: dict({ dict: dict({
isTree: true, isTree: true,
@@ -217,7 +214,7 @@ export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProp
label: 'name' label: 'name'
}), }),
column: { column: {
minWidth: 200, //最小列宽 minWidth: 300, //最小列宽
formatter({ value, row, index }) { formatter({ value, row, index }) {
return row.dept_name_all 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: { role: {
title: '角色', title: '角色',
search: { search: {
@@ -378,6 +408,9 @@ export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProp
dict: dict({ dict: dict({
data: dictionary('button_status_bool'), data: dictionary('button_status_bool'),
}), }),
form: {
value: true
}
}, },
avatar: { avatar: {
title: '头像', title: '头像',
@@ -392,8 +425,8 @@ export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProp
}, },
...commonCrudConfig({ ...commonCrudConfig({
dept_belong_id: { dept_belong_id: {
form: true, form: false,
table: true table: false
} }
}) })
}, },