Merge remote-tracking branch 'origin/develop' into develop
This commit is contained in:
@@ -404,7 +404,7 @@ PLUGINS_URL_PATTERNS = []
|
|||||||
# ********** 一键导入插件配置开始 **********
|
# ********** 一键导入插件配置开始 **********
|
||||||
# 例如:
|
# 例如:
|
||||||
# from dvadmin_upgrade_center.settings import * # 升级中心
|
# from dvadmin_upgrade_center.settings import * # 升级中心
|
||||||
from dvadmin3_celery.settings import * # celery 异步任务
|
# from dvadmin3_celery.settings import * # celery 异步任务
|
||||||
# from dvadmin_third.settings import * # 第三方用户管理
|
# from dvadmin_third.settings import * # 第三方用户管理
|
||||||
# from dvadmin_ak_sk.settings import * # 秘钥管理管理
|
# from dvadmin_ak_sk.settings import * # 秘钥管理管理
|
||||||
# from dvadmin_tenants.settings import * # 租户管理
|
# from dvadmin_tenants.settings import * # 租户管理
|
||||||
|
|||||||
@@ -26,6 +26,12 @@ class RoleSerializer(CustomModelSerializer):
|
|||||||
"""
|
"""
|
||||||
角色-序列化器
|
角色-序列化器
|
||||||
"""
|
"""
|
||||||
|
users = serializers.SerializerMethodField()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_users(instance):
|
||||||
|
users = instance.users_set.exclude(id=1).values('id', 'name', 'dept__name')
|
||||||
|
return users
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Role
|
model = Role
|
||||||
@@ -116,3 +122,23 @@ class RoleViewSet(CustomModelViewSet, FastCrudMixin,FieldPermissionMixin):
|
|||||||
create_serializer_class = RoleCreateUpdateSerializer
|
create_serializer_class = RoleCreateUpdateSerializer
|
||||||
update_serializer_class = RoleCreateUpdateSerializer
|
update_serializer_class = RoleCreateUpdateSerializer
|
||||||
search_fields = ['name', 'key']
|
search_fields = ['name', 'key']
|
||||||
|
|
||||||
|
@action(methods=['PUT'], detail=True, permission_classes=[IsAuthenticated])
|
||||||
|
def set_role_users(self, request, pk):
|
||||||
|
"""
|
||||||
|
设置 角色-用户
|
||||||
|
:param request:
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
data = request.data
|
||||||
|
direction = data.get('direction')
|
||||||
|
movedKeys = data.get('movedKeys')
|
||||||
|
role = Role.objects.get(pk=pk)
|
||||||
|
if direction == "left":
|
||||||
|
# left : 移除用户权限
|
||||||
|
role.users_set.remove(*movedKeys)
|
||||||
|
else:
|
||||||
|
# right : 添加用户权限
|
||||||
|
role.users_set.add(*movedKeys)
|
||||||
|
serializer = RoleSerializer(role)
|
||||||
|
return DetailResponse(data=serializer.data, msg="更新成功")
|
||||||
@@ -6,24 +6,20 @@
|
|||||||
@Created on: 2021/6/3 003 0:30
|
@Created on: 2021/6/3 003 0:30
|
||||||
@Remark: 菜单按钮管理
|
@Remark: 菜单按钮管理
|
||||||
"""
|
"""
|
||||||
from django.db.models import F, Subquery, OuterRef, Exists, BooleanField, Q, Case, Value, When
|
|
||||||
from django.db.models.functions import Coalesce
|
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
from rest_framework.decorators import action
|
from rest_framework.decorators import action
|
||||||
from rest_framework.fields import ListField
|
|
||||||
from rest_framework.permissions import IsAuthenticated
|
from rest_framework.permissions import IsAuthenticated
|
||||||
|
|
||||||
from dvadmin.system.models import RoleMenuButtonPermission, Menu, MenuButton, Dept, RoleMenuPermission, FieldPermission, \
|
from dvadmin.system.models import RoleMenuButtonPermission, Menu, Dept, MenuButton, RoleMenuPermission, \
|
||||||
MenuField
|
MenuField, FieldPermission
|
||||||
from dvadmin.system.views.menu import MenuSerializer
|
from dvadmin.utils.json_response import DetailResponse
|
||||||
from dvadmin.utils.json_response import DetailResponse, ErrorResponse
|
|
||||||
from dvadmin.utils.serializers import CustomModelSerializer
|
from dvadmin.utils.serializers import CustomModelSerializer
|
||||||
from dvadmin.utils.viewset import CustomModelViewSet
|
from dvadmin.utils.viewset import CustomModelViewSet
|
||||||
|
|
||||||
|
|
||||||
class RoleMenuButtonPermissionSerializer(CustomModelSerializer):
|
class RoleMenuButtonPermissionSerializer(CustomModelSerializer):
|
||||||
"""
|
"""
|
||||||
菜单按钮-序列化器
|
角色-菜单-按钮-权限 查询序列化
|
||||||
"""
|
"""
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
@@ -34,7 +30,7 @@ class RoleMenuButtonPermissionSerializer(CustomModelSerializer):
|
|||||||
|
|
||||||
class RoleMenuButtonPermissionCreateUpdateSerializer(CustomModelSerializer):
|
class RoleMenuButtonPermissionCreateUpdateSerializer(CustomModelSerializer):
|
||||||
"""
|
"""
|
||||||
初始化菜单按钮-序列化器
|
角色-菜单-按钮-权限 创建/修改序列化
|
||||||
"""
|
"""
|
||||||
menu_button__name = serializers.CharField(source='menu_button.name', read_only=True)
|
menu_button__name = serializers.CharField(source='menu_button.name', read_only=True)
|
||||||
menu_button__value = serializers.CharField(source='menu_button.value', read_only=True)
|
menu_button__value = serializers.CharField(source='menu_button.value', read_only=True)
|
||||||
@@ -45,63 +41,99 @@ class RoleMenuButtonPermissionCreateUpdateSerializer(CustomModelSerializer):
|
|||||||
read_only_fields = ["id"]
|
read_only_fields = ["id"]
|
||||||
|
|
||||||
|
|
||||||
class RoleButtonPermissionSerializer(CustomModelSerializer):
|
class RoleMenuSerializer(CustomModelSerializer):
|
||||||
"""
|
"""
|
||||||
角色按钮权限
|
角色-菜单 序列化
|
||||||
"""
|
"""
|
||||||
isCheck = serializers.SerializerMethodField()
|
isCheck = serializers.SerializerMethodField()
|
||||||
data_range = serializers.SerializerMethodField()
|
|
||||||
|
|
||||||
def get_isCheck(self, instance):
|
def get_isCheck(self, instance):
|
||||||
params = self.request.query_params
|
params = self.request.query_params
|
||||||
|
data = self.request.data
|
||||||
|
return RoleMenuPermission.objects.filter(
|
||||||
|
menu_id=instance.id,
|
||||||
|
role_id=params.get('roleId', data.get('roleId')),
|
||||||
|
).exists()
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = Menu
|
||||||
|
fields = ["id", "name", "parent", "is_catalog", "isCheck"]
|
||||||
|
|
||||||
|
|
||||||
|
class RoleMenuButtonSerializer(CustomModelSerializer):
|
||||||
|
"""
|
||||||
|
角色-菜单-按钮 序列化
|
||||||
|
"""
|
||||||
|
isCheck = serializers.SerializerMethodField()
|
||||||
|
data_range = serializers.SerializerMethodField()
|
||||||
|
role_menu_btn_perm_id = serializers.SerializerMethodField()
|
||||||
|
dept = serializers.SerializerMethodField()
|
||||||
|
|
||||||
|
def get_isCheck(self, instance):
|
||||||
|
params = self.request.query_params
|
||||||
|
data = self.request.data
|
||||||
return RoleMenuButtonPermission.objects.filter(
|
return RoleMenuButtonPermission.objects.filter(
|
||||||
menu_button__id=instance['id'],
|
menu_button_id=instance.id,
|
||||||
role__id=params.get('role'),
|
role_id=params.get('roleId', data.get('roleId')),
|
||||||
).exists()
|
).exists()
|
||||||
|
|
||||||
def get_data_range(self, instance):
|
def get_data_range(self, instance):
|
||||||
params = self.request.query_params
|
obj = self.get_role_menu_btn_prem(instance)
|
||||||
obj = RoleMenuButtonPermission.objects.filter(
|
|
||||||
menu_button__id=instance['id'],
|
|
||||||
role__id=params.get('role'),
|
|
||||||
).first()
|
|
||||||
if obj is None:
|
if obj is None:
|
||||||
return None
|
return None
|
||||||
return obj.data_range
|
return obj.data_range
|
||||||
|
|
||||||
|
def get_role_menu_btn_perm_id(self, instance):
|
||||||
|
obj = self.get_role_menu_btn_prem(instance)
|
||||||
|
if obj is None:
|
||||||
|
return None
|
||||||
|
return obj.id
|
||||||
|
|
||||||
|
def get_dept(self, instance):
|
||||||
|
obj = self.get_role_menu_btn_prem(instance)
|
||||||
|
if obj is None:
|
||||||
|
return None
|
||||||
|
return obj.dept.all().values_list('id', flat=True)
|
||||||
|
|
||||||
|
def get_role_menu_btn_prem(self, instance):
|
||||||
|
params = self.request.query_params
|
||||||
|
data = self.request.data
|
||||||
|
obj = RoleMenuButtonPermission.objects.filter(
|
||||||
|
menu_button_id=instance.id,
|
||||||
|
role_id=params.get('roleId', data.get('roleId')),
|
||||||
|
).first()
|
||||||
|
return obj
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = MenuButton
|
model = MenuButton
|
||||||
fields = ['id', 'name', 'value', 'isCheck', 'data_range']
|
fields = ['id', 'menu', 'name', 'isCheck', 'data_range', 'role_menu_btn_perm_id', 'dept']
|
||||||
|
|
||||||
|
|
||||||
class RoleFieldPermissionSerializer(CustomModelSerializer):
|
|
||||||
class Meta:
|
|
||||||
model = FieldPermission
|
|
||||||
fields = "__all__"
|
|
||||||
|
|
||||||
|
|
||||||
class RoleMenuFieldSerializer(CustomModelSerializer):
|
class RoleMenuFieldSerializer(CustomModelSerializer):
|
||||||
|
"""
|
||||||
|
角色-菜单-字段 序列化
|
||||||
|
"""
|
||||||
is_query = serializers.SerializerMethodField()
|
is_query = serializers.SerializerMethodField()
|
||||||
is_create = serializers.SerializerMethodField()
|
is_create = serializers.SerializerMethodField()
|
||||||
is_update = serializers.SerializerMethodField()
|
is_update = serializers.SerializerMethodField()
|
||||||
|
|
||||||
def get_is_query(self, instance):
|
def get_is_query(self, instance):
|
||||||
params = self.request.query_params
|
params = self.request.query_params
|
||||||
queryset = instance.menu_field.filter(role=params.get('role')).first()
|
queryset = instance.menu_field.filter(role=params.get('roleId')).first()
|
||||||
if queryset:
|
if queryset:
|
||||||
return queryset.is_query
|
return queryset.is_query
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def get_is_create(self, instance):
|
def get_is_create(self, instance):
|
||||||
params = self.request.query_params
|
params = self.request.query_params
|
||||||
queryset = instance.menu_field.filter(role=params.get('role')).first()
|
queryset = instance.menu_field.filter(role=params.get('roleId')).first()
|
||||||
if queryset:
|
if queryset:
|
||||||
return queryset.is_create
|
return queryset.is_create
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def get_is_update(self, instance):
|
def get_is_update(self, instance):
|
||||||
params = self.request.query_params
|
params = self.request.query_params
|
||||||
queryset = instance.menu_field.filter(role=params.get('role')).first()
|
queryset = instance.menu_field.filter(role=params.get('roleId')).first()
|
||||||
if queryset:
|
if queryset:
|
||||||
return queryset.is_update
|
return queryset.is_update
|
||||||
return False
|
return False
|
||||||
@@ -111,54 +143,6 @@ class RoleMenuFieldSerializer(CustomModelSerializer):
|
|||||||
fields = ['id', 'field_name', 'title', 'is_query', 'is_create', 'is_update']
|
fields = ['id', 'field_name', 'title', 'is_query', 'is_create', 'is_update']
|
||||||
|
|
||||||
|
|
||||||
class RoleMenuSerializer(CustomModelSerializer):
|
|
||||||
menus = serializers.SerializerMethodField()
|
|
||||||
|
|
||||||
def get_menus(self, instance):
|
|
||||||
menu_list = Menu.objects.filter(parent=instance['id']).values('id', 'name')
|
|
||||||
serializer = RoleMenuPermissionSerializer(menu_list, many=True, request=self.request)
|
|
||||||
return serializer.data
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
model = Menu
|
|
||||||
fields = ['id', 'name', 'menus']
|
|
||||||
|
|
||||||
|
|
||||||
class RoleMenuPermissionSerializer(CustomModelSerializer):
|
|
||||||
"""
|
|
||||||
菜单和按钮权限
|
|
||||||
"""
|
|
||||||
# name = serializers.SerializerMethodField()
|
|
||||||
isCheck = serializers.SerializerMethodField()
|
|
||||||
btns = serializers.SerializerMethodField()
|
|
||||||
columns = serializers.SerializerMethodField()
|
|
||||||
|
|
||||||
# def get_name(self, instance):
|
|
||||||
# parent_list = Menu.get_all_parent(instance['id'])
|
|
||||||
# names = [d["name"] for d in parent_list]
|
|
||||||
# return "/".join(names)
|
|
||||||
def get_isCheck(self, instance):
|
|
||||||
params = self.request.query_params
|
|
||||||
return RoleMenuPermission.objects.filter(
|
|
||||||
menu__id=instance['id'],
|
|
||||||
role__id=params.get('role'),
|
|
||||||
).exists()
|
|
||||||
|
|
||||||
def get_btns(self, instance):
|
|
||||||
btn_list = MenuButton.objects.filter(menu__id=instance['id']).values('id', 'name', 'value')
|
|
||||||
serializer = RoleButtonPermissionSerializer(btn_list, many=True, request=self.request)
|
|
||||||
return serializer.data
|
|
||||||
|
|
||||||
def get_columns(self, instance):
|
|
||||||
col_list = MenuField.objects.filter(menu=instance['id'])
|
|
||||||
serializer = RoleMenuFieldSerializer(col_list, many=True, request=self.request)
|
|
||||||
return serializer.data
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
model = Menu
|
|
||||||
fields = ['id', 'name', 'isCheck', 'btns', 'columns']
|
|
||||||
|
|
||||||
|
|
||||||
class RoleMenuButtonPermissionViewSet(CustomModelViewSet):
|
class RoleMenuButtonPermissionViewSet(CustomModelViewSet):
|
||||||
"""
|
"""
|
||||||
菜单按钮接口
|
菜单按钮接口
|
||||||
@@ -174,202 +158,103 @@ class RoleMenuButtonPermissionViewSet(CustomModelViewSet):
|
|||||||
update_serializer_class = RoleMenuButtonPermissionCreateUpdateSerializer
|
update_serializer_class = RoleMenuButtonPermissionCreateUpdateSerializer
|
||||||
extra_filter_class = []
|
extra_filter_class = []
|
||||||
|
|
||||||
# @action(methods=['GET'], detail=False, permission_classes=[IsAuthenticated])
|
@action(methods=['GET'], detail=False, permission_classes=[IsAuthenticated])
|
||||||
# def get_role_premission(self, request):
|
def get_role_menu(self, request):
|
||||||
# """
|
"""
|
||||||
# 角色授权获取:
|
获取 角色-菜单
|
||||||
# :param request: role
|
:param request:
|
||||||
# :return: menu,btns,columns
|
:return:
|
||||||
# """
|
"""
|
||||||
# params = request.query_params
|
menu_queryset = Menu.objects.all()
|
||||||
# is_superuser = request.user.is_superuser
|
serializer = RoleMenuSerializer(menu_queryset, many=True, request=request)
|
||||||
# if is_superuser:
|
return DetailResponse(data=serializer.data)
|
||||||
# queryset = Menu.objects.filter(status=1, is_catalog=True).values('name', 'id').all()
|
|
||||||
# else:
|
@action(methods=['PUT'], detail=False, permission_classes=[IsAuthenticated])
|
||||||
# role_id = request.user.role.values_list('id', flat=True)
|
def set_role_menu(self, request):
|
||||||
# menu_list = RoleMenuPermission.objects.filter(role__in=role_id).values_list('menu__id', flat=True)
|
"""
|
||||||
# queryset = Menu.objects.filter(status=1, is_catalog=True, id__in=menu_list).values('name', 'id').all()
|
设置 角色-菜单
|
||||||
# serializer = RoleMenuSerializer(queryset, many=True, request=request)
|
:param request:
|
||||||
# data = serializer.data
|
:return:
|
||||||
# return DetailResponse(data=data)
|
"""
|
||||||
|
data = request.data
|
||||||
|
roleId = data.get('roleId')
|
||||||
|
menuId = data.get('menuId')
|
||||||
|
isCheck = data.get('isCheck')
|
||||||
|
if isCheck:
|
||||||
|
# 添加权限:创建关联记录
|
||||||
|
instance = RoleMenuPermission.objects.create(role_id=roleId, menu_id=menuId)
|
||||||
|
else:
|
||||||
|
# 删除权限:移除关联记录
|
||||||
|
RoleMenuPermission.objects.filter(role_id=roleId, menu_id=menuId).delete()
|
||||||
|
menu_instance = Menu.objects.get(id=menuId)
|
||||||
|
serializer = RoleMenuSerializer(menu_instance, request=request)
|
||||||
|
return DetailResponse(data=serializer.data, msg="更新成功")
|
||||||
|
|
||||||
@action(methods=['GET'], detail=False, permission_classes=[IsAuthenticated])
|
@action(methods=['GET'], detail=False, permission_classes=[IsAuthenticated])
|
||||||
def get_role_permission(self, request):
|
def get_role_menu_btn_field(self, request):
|
||||||
|
"""
|
||||||
|
获取 角色-菜单-按钮-列字段
|
||||||
|
:param request:
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
params = request.query_params
|
params = request.query_params
|
||||||
# 需要授权的角色信息
|
menuId = params.get('menuId', None)
|
||||||
current_role = params.get('role', None)
|
menu_btn_queryset = MenuButton.objects.filter(menu_id=menuId)
|
||||||
# 当前登录用户的角色
|
menu_btn_serializer = RoleMenuButtonSerializer(menu_btn_queryset, many=True, request=request)
|
||||||
role_list = request.user.role.values_list('id', flat=True)
|
menu_field_queryset = MenuField.objects.filter(menu_id=menuId)
|
||||||
if current_role is None:
|
menu_field_serializer = RoleMenuFieldSerializer(menu_field_queryset, many=True, request=request)
|
||||||
return ErrorResponse(msg='参数错误')
|
return DetailResponse(data={'menu_btn': menu_btn_serializer.data, 'menu_field': menu_field_serializer.data})
|
||||||
is_superuser = request.user.is_superuser
|
|
||||||
if is_superuser:
|
|
||||||
menu_queryset = Menu.objects.prefetch_related('menuPermission').prefetch_related(
|
|
||||||
'menufield_set')
|
|
||||||
else:
|
|
||||||
role_id_list = request.user.role.values_list('id', flat=True)
|
|
||||||
menu_list = RoleMenuPermission.objects.filter(role__in=role_id_list).values_list('menu__id', flat=True)
|
|
||||||
|
|
||||||
# 当前角色已授权的菜单
|
|
||||||
menu_queryset = Menu.objects.filter(id__in=menu_list).prefetch_related('menuPermission').prefetch_related(
|
|
||||||
'menufield_set')
|
|
||||||
result = []
|
|
||||||
for menu_item in menu_queryset:
|
|
||||||
isCheck = RoleMenuPermission.objects.filter(
|
|
||||||
menu_id=menu_item.id,
|
|
||||||
role_id=current_role
|
|
||||||
).exists()
|
|
||||||
dicts = {
|
|
||||||
'name': menu_item.name,
|
|
||||||
'id': menu_item.id,
|
|
||||||
'parent': menu_item.parent.id if menu_item.parent else None,
|
|
||||||
'isCheck': isCheck,
|
|
||||||
'btns': [],
|
|
||||||
'columns': []
|
|
||||||
}
|
|
||||||
for mb_item in menu_item.menuPermission.all():
|
|
||||||
rolemenubuttonpermission_queryset = RoleMenuButtonPermission.objects.filter(
|
|
||||||
menu_button_id=mb_item.id,
|
|
||||||
role_id=current_role
|
|
||||||
).first()
|
|
||||||
dicts['btns'].append(
|
|
||||||
{
|
|
||||||
'id': mb_item.id,
|
|
||||||
'name': mb_item.name,
|
|
||||||
'value': mb_item.value,
|
|
||||||
'data_range': rolemenubuttonpermission_queryset.data_range
|
|
||||||
if rolemenubuttonpermission_queryset
|
|
||||||
else None,
|
|
||||||
'isCheck': bool(rolemenubuttonpermission_queryset),
|
|
||||||
'dept': rolemenubuttonpermission_queryset.dept.all().values_list('id', flat=True)
|
|
||||||
if rolemenubuttonpermission_queryset
|
|
||||||
else [],
|
|
||||||
}
|
|
||||||
)
|
|
||||||
for column_item in menu_item.menufield_set.all():
|
|
||||||
# 需要授权角色已拥有的列权限
|
|
||||||
fieldpermission_queryset = column_item.menu_field.filter(role_id=current_role).first()
|
|
||||||
is_query = fieldpermission_queryset.is_query if fieldpermission_queryset else False
|
|
||||||
is_create = fieldpermission_queryset.is_create if fieldpermission_queryset else False
|
|
||||||
is_update = fieldpermission_queryset.is_update if fieldpermission_queryset else False
|
|
||||||
# 当前登录用户角色可分配的列权限
|
|
||||||
fieldpermission_queryset_disabled = column_item.menu_field.filter(role_id__in=role_list).first()
|
|
||||||
disabled_query = fieldpermission_queryset_disabled.is_query if fieldpermission_queryset_disabled else True
|
|
||||||
disabled_create = fieldpermission_queryset_disabled.is_create if fieldpermission_queryset_disabled else True
|
|
||||||
disabled_update = fieldpermission_queryset_disabled.is_update if fieldpermission_queryset_disabled else True
|
|
||||||
|
|
||||||
dicts['columns'].append({
|
|
||||||
'id': column_item.id,
|
|
||||||
'field_name': column_item.field_name,
|
|
||||||
'title': column_item.title,
|
|
||||||
'is_query': is_query,
|
|
||||||
'is_create': is_create,
|
|
||||||
'is_update': is_update,
|
|
||||||
'disabled_query': False if is_superuser else not disabled_query,
|
|
||||||
'disabled_create': False if is_superuser else not disabled_create,
|
|
||||||
'disabled_update': False if is_superuser else not disabled_update,
|
|
||||||
})
|
|
||||||
result.append(dicts)
|
|
||||||
return DetailResponse(data=result)
|
|
||||||
|
|
||||||
@action(methods=['PUT'], detail=True, permission_classes=[IsAuthenticated])
|
@action(methods=['PUT'], detail=True, permission_classes=[IsAuthenticated])
|
||||||
def set_role_premission(self, request, pk):
|
def set_role_menu_field(self, request, pk):
|
||||||
"""
|
"""
|
||||||
对角色的菜单和按钮及按钮范围授权:
|
设置 角色-菜单-列字段
|
||||||
:param request:
|
|
||||||
:param pk: role
|
|
||||||
:return:
|
|
||||||
"""
|
"""
|
||||||
body = request.data
|
data = request.data
|
||||||
RoleMenuPermission.objects.filter(role=pk).delete()
|
for col in data:
|
||||||
RoleMenuButtonPermission.objects.filter(role=pk).delete()
|
FieldPermission.objects.update_or_create(
|
||||||
for item in body:
|
role_id=pk, field_id=col.get('id'),
|
||||||
if item.get('isCheck'):
|
defaults={
|
||||||
RoleMenuPermission.objects.create(role_id=pk, menu_id=item["id"])
|
'is_create': col.get('is_create'),
|
||||||
for btn in item.get('btns'):
|
'is_update': col.get('is_update'),
|
||||||
if btn.get('isCheck'):
|
'is_query': col.get('is_query'),
|
||||||
data_range = btn.get('data_range', 0) or 0
|
})
|
||||||
instance = RoleMenuButtonPermission.objects.create(role_id=pk, menu_button_id=btn.get('id'),
|
|
||||||
data_range=data_range)
|
|
||||||
instance.dept.set(btn.get('dept', []))
|
|
||||||
for col in item.get('columns'):
|
|
||||||
FieldPermission.objects.update_or_create(role_id=pk, field_id=col.get('id'),
|
|
||||||
defaults={
|
|
||||||
'is_query': col.get('is_query'),
|
|
||||||
'is_create': col.get('is_create'),
|
|
||||||
'is_update': col.get('is_update')
|
|
||||||
})
|
|
||||||
return DetailResponse(msg="授权成功")
|
|
||||||
|
|
||||||
@action(methods=['GET'], detail=False, permission_classes=[IsAuthenticated])
|
return DetailResponse(data=[], msg="更新成功")
|
||||||
def role_menu_get_button(self, request):
|
|
||||||
"""
|
|
||||||
当前用户角色和菜单获取可下拉选项的按钮:角色授权页面使用
|
|
||||||
:param request:
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
if params := request.query_params:
|
|
||||||
if menu_id := params.get('menu', None):
|
|
||||||
is_superuser = request.user.is_superuser
|
|
||||||
if is_superuser:
|
|
||||||
queryset = MenuButton.objects.filter(menu=menu_id).values('id', 'name')
|
|
||||||
else:
|
|
||||||
role_list = request.user.role.values_list('id', flat=True)
|
|
||||||
queryset = RoleMenuButtonPermission.objects.filter(
|
|
||||||
role__in=role_list, menu_button__menu=menu_id
|
|
||||||
).values(btn_id=F('menu_button__id'), name=F('menu_button__name'))
|
|
||||||
return DetailResponse(data=queryset)
|
|
||||||
return ErrorResponse(msg="参数错误")
|
|
||||||
|
|
||||||
@action(methods=['GET'], detail=False, permission_classes=[IsAuthenticated])
|
@action(methods=['PUT'], detail=False, permission_classes=[IsAuthenticated])
|
||||||
def data_scope(self, request):
|
def set_role_menu_btn(self, request):
|
||||||
"""
|
"""
|
||||||
获取数据权限范围:角色授权页面使用
|
设置 角色-菜单-按钮
|
||||||
:param request:
|
|
||||||
:return:
|
|
||||||
"""
|
"""
|
||||||
is_superuser = request.user.is_superuser
|
data = request.data
|
||||||
if is_superuser:
|
isCheck = data.get('isCheck', None)
|
||||||
data = [
|
roleId = data.get('roleId', None)
|
||||||
{"value": 0, "label": '仅本人数据权限'},
|
btnId = data.get('btnId', None)
|
||||||
{"value": 1, "label": '本部门及以下数据权限'},
|
if isCheck:
|
||||||
{"value": 2, "label": '本部门数据权限'},
|
# 添加权限:创建关联记录
|
||||||
{"value": 3, "label": '全部数据权限'},
|
RoleMenuButtonPermission.objects.create(role_id=roleId, menu_button_id=btnId)
|
||||||
{"value": 4, "label": '自定义数据权限'}
|
|
||||||
]
|
|
||||||
return DetailResponse(data=data)
|
|
||||||
else:
|
else:
|
||||||
params = request.query_params
|
# 删除权限:移除关联记录
|
||||||
data = [{"value": 0, "label": '仅本人数据权限'}]
|
RoleMenuButtonPermission.objects.filter(role_id=roleId, menu_button_id=btnId).delete()
|
||||||
role_list = request.user.role.values_list('id', flat=True)
|
menu_btn_instance = MenuButton.objects.get(id=btnId)
|
||||||
# 权限页面进入初始化获取所有的数据权限范围
|
serializer = RoleMenuButtonSerializer(menu_btn_instance, request=request)
|
||||||
role_queryset = RoleMenuButtonPermission.objects.filter(
|
return DetailResponse(data=serializer.data, msg="更新成功")
|
||||||
role__in=role_list
|
|
||||||
).values_list('data_range', flat=True)
|
|
||||||
# 通过按钮小齿轮获取指定按钮的权限
|
|
||||||
if menu_button_id := params.get('menu_button', None):
|
|
||||||
role_queryset = RoleMenuButtonPermission.objects.filter(
|
|
||||||
role__in=role_list, menu_button__id=menu_button_id
|
|
||||||
).values_list('data_range', flat=True)
|
|
||||||
|
|
||||||
data_range_list = list(set(role_queryset))
|
@action(methods=['PUT'], detail=False, permission_classes=[IsAuthenticated])
|
||||||
for item in data_range_list:
|
def set_role_menu_btn_data_range(self, request):
|
||||||
if item == 0:
|
"""
|
||||||
data = data
|
设置 角色-菜单-按钮-权限
|
||||||
elif item == 1:
|
"""
|
||||||
data.extend([
|
data = request.data
|
||||||
{"value": 1, "label": '本部门及以下数据权限'},
|
instance = RoleMenuButtonPermission.objects.get(id=data.get('role_menu_btn_perm_id'))
|
||||||
{"value": 2, "label": '本部门数据权限'}
|
instance.data_range = data.get('data_range')
|
||||||
])
|
instance.dept.add(*data.get('dept'))
|
||||||
elif item == 2:
|
if not data.get('dept'):
|
||||||
data.extend([{"value": 2, "label": '本部门数据权限'}])
|
instance.dept.clear()
|
||||||
elif item == 3:
|
instance.save()
|
||||||
data.extend([{"value": 3, "label": '全部数据权限'}])
|
serializer = RoleMenuButtonPermissionSerializer(instance, request=request)
|
||||||
elif item == 4:
|
return DetailResponse(data=serializer.data, msg="更新成功")
|
||||||
data.extend([{"value": 4, "label": '自定义数据权限'}])
|
|
||||||
else:
|
|
||||||
data = []
|
|
||||||
return DetailResponse(data=data)
|
|
||||||
|
|
||||||
@action(methods=['get'], detail=False, permission_classes=[IsAuthenticated])
|
@action(methods=['get'], detail=False, permission_classes=[IsAuthenticated])
|
||||||
def role_to_dept_all(self, request):
|
def role_to_dept_all(self, request):
|
||||||
@@ -395,55 +280,3 @@ class RoleMenuButtonPermissionViewSet(CustomModelViewSet):
|
|||||||
dept["disabled"] = False if is_superuser else dept["id"] not in dept_checked_disabled
|
dept["disabled"] = False if is_superuser else dept["id"] not in dept_checked_disabled
|
||||||
data.append(dept)
|
data.append(dept)
|
||||||
return DetailResponse(data=data)
|
return DetailResponse(data=data)
|
||||||
|
|
||||||
@action(methods=['get'], detail=False, permission_classes=[IsAuthenticated])
|
|
||||||
def menu_to_button(self, request):
|
|
||||||
"""
|
|
||||||
根据所选择菜单获取已配置的按钮/接口权限:角色授权页面使用
|
|
||||||
:param request:
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
params = request.query_params
|
|
||||||
menu_id = params.get('menu', None)
|
|
||||||
if menu_id is None:
|
|
||||||
return ErrorResponse(msg="未获取到参数")
|
|
||||||
is_superuser = request.user.is_superuser
|
|
||||||
if is_superuser:
|
|
||||||
queryset = RoleMenuButtonPermission.objects.filter(menu_button__menu=menu_id).values(
|
|
||||||
'id',
|
|
||||||
'data_range',
|
|
||||||
'menu_button',
|
|
||||||
'menu_button__name',
|
|
||||||
'menu_button__value'
|
|
||||||
)
|
|
||||||
return DetailResponse(data=queryset)
|
|
||||||
else:
|
|
||||||
if params:
|
|
||||||
|
|
||||||
role_id = params.get('role', None)
|
|
||||||
if role_id is None:
|
|
||||||
return ErrorResponse(msg="未获取到参数")
|
|
||||||
queryset = RoleMenuButtonPermission.objects.filter(role=role_id, menu_button__menu=menu_id).values(
|
|
||||||
'id',
|
|
||||||
'data_range',
|
|
||||||
'menu_button',
|
|
||||||
'menu_button__name',
|
|
||||||
'menu_button__value'
|
|
||||||
)
|
|
||||||
return DetailResponse(data=queryset)
|
|
||||||
return ErrorResponse(msg="未获取到参数")
|
|
||||||
|
|
||||||
@action(methods=['get'], detail=False, permission_classes=[IsAuthenticated])
|
|
||||||
def role_to_menu(self, request):
|
|
||||||
"""
|
|
||||||
获取角色对应的按钮权限
|
|
||||||
:param request:
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
params = request.query_params
|
|
||||||
role_id = params.get('role', None)
|
|
||||||
if role_id is None:
|
|
||||||
return ErrorResponse(msg="未获取到参数")
|
|
||||||
queryset = RoleMenuPermission.objects.filter(role_id=role_id).values_list('menu_id', flat=True).distinct()
|
|
||||||
|
|
||||||
return DetailResponse(data=queryset)
|
|
||||||
|
|||||||
@@ -1,71 +1,43 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
from itertools import groupby
|
|
||||||
|
|
||||||
from django.db.models import F
|
from django.db.models import F
|
||||||
from rest_framework.decorators import action
|
from rest_framework.decorators import action
|
||||||
from rest_framework.permissions import IsAuthenticated
|
from rest_framework.permissions import IsAuthenticated
|
||||||
|
|
||||||
from dvadmin.system.models import FieldPermission, MenuField
|
from dvadmin.system.models import FieldPermission, MenuField
|
||||||
from dvadmin.utils.json_response import DetailResponse
|
from dvadmin.utils.json_response import DetailResponse
|
||||||
from dvadmin.utils.models import get_custom_app_models
|
|
||||||
|
|
||||||
|
def merge_permission(data):
|
||||||
|
"""
|
||||||
|
合并权限
|
||||||
|
"""
|
||||||
|
result = {}
|
||||||
|
for item in data:
|
||||||
|
field_name = item.pop('field_name')
|
||||||
|
if field_name not in result:
|
||||||
|
result[field_name] = item
|
||||||
|
else:
|
||||||
|
for key, value in item.items():
|
||||||
|
result[field_name][key] = result[field_name][key] or value
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
class FieldPermissionMixin:
|
class FieldPermissionMixin:
|
||||||
@action(methods=['get'], detail=False,permission_classes=[IsAuthenticated])
|
@action(methods=['get'], detail=False, permission_classes=[IsAuthenticated])
|
||||||
def field_permission(self, request):
|
def field_permission(self, request):
|
||||||
"""
|
"""
|
||||||
获取字段权限
|
获取字段权限
|
||||||
"""
|
"""
|
||||||
finded = False
|
model = self.serializer_class.Meta.model.__name__
|
||||||
for model in get_custom_app_models():
|
|
||||||
if model['object'] is self.serializer_class.Meta.model:
|
|
||||||
finded = True
|
|
||||||
break
|
|
||||||
if finded:
|
|
||||||
break
|
|
||||||
if finded is False:
|
|
||||||
return []
|
|
||||||
user = request.user
|
user = request.user
|
||||||
if user.is_superuser==1:
|
# 创建一个默认字典来存储最终的结果
|
||||||
data = MenuField.objects.filter( model=model['model']).values('field_name')
|
if user.is_superuser == 1:
|
||||||
for item in data:
|
data = MenuField.objects.filter(model=model).values('field_name')
|
||||||
item['is_create'] = True
|
result = {item['field_name']: {"is_create": True, "is_query": True, "is_update": True} for item in data}
|
||||||
item['is_query'] = True
|
|
||||||
item['is_update'] = True
|
|
||||||
else:
|
else:
|
||||||
roles = request.user.role.values_list('id', flat=True)
|
roles = request.user.role.values_list('id', flat=True)
|
||||||
data= FieldPermission.objects.filter(
|
data = FieldPermission.objects.filter(
|
||||||
field__model=model['model'],role__in=roles
|
field__model=model, role__in=roles
|
||||||
).values( 'is_create', 'is_query', 'is_update',field_name=F('field__field_name'))
|
).values('is_create', 'is_query', 'is_update', field_name=F('field__field_name'))
|
||||||
|
result = merge_permission(data)
|
||||||
"""
|
return DetailResponse(data=result)
|
||||||
合并权限
|
|
||||||
|
|
||||||
这段代码首先根据 field_name 对列表进行排序,
|
|
||||||
然后使用 groupby 按 field_name 进行分组。
|
|
||||||
对于每个组,它创建一个新的字典 merged,
|
|
||||||
并遍历组中的每个字典,将布尔值字段使用逻辑或(or)操作符进行合并(如果 merged 中还没有该字段,则默认为 False),
|
|
||||||
其他字段(如 field_name)则直接取组的关键字(即 key)
|
|
||||||
"""
|
|
||||||
|
|
||||||
# 使用field_name对列表进行分组, # groupby 需要先对列表进行排序,因为它只能对连续相同的元素进行分组。
|
|
||||||
grouped = groupby(sorted(list(data), key=lambda x: x['field_name']), key=lambda x: x['field_name'])
|
|
||||||
|
|
||||||
data = []
|
|
||||||
|
|
||||||
# 遍历分组,合并权限
|
|
||||||
for key, group in grouped:
|
|
||||||
|
|
||||||
# 初始化一个空字典来存储合并后的结果
|
|
||||||
merged = {}
|
|
||||||
for item in group:
|
|
||||||
# 合并权限, True值优先
|
|
||||||
merged['is_create'] = merged.get('is_create', False) or item['is_create']
|
|
||||||
merged['is_query'] = merged.get('is_query', False) or item['is_query']
|
|
||||||
merged['is_update'] = merged.get('is_update', False) or item['is_update']
|
|
||||||
merged['field_name'] = key
|
|
||||||
|
|
||||||
data.append(merged)
|
|
||||||
|
|
||||||
return DetailResponse(data=data)
|
|
||||||
|
|||||||
@@ -340,7 +340,7 @@ class CustomDjangoFilterBackend(DjangoFilterBackend):
|
|||||||
from timezone_field import TimeZoneField
|
from timezone_field import TimeZoneField
|
||||||
|
|
||||||
# 不进行 过滤的model 类
|
# 不进行 过滤的model 类
|
||||||
if isinstance(field, (models.JSONField, TimeZoneField)):
|
if isinstance(field, (models.JSONField, TimeZoneField, models.FileField)):
|
||||||
continue
|
continue
|
||||||
# warn if the field doesn't exist.
|
# warn if the field doesn't exist.
|
||||||
if field is None:
|
if field is None:
|
||||||
|
|||||||
@@ -86,4 +86,5 @@ def import_to_data(file_url, field_data, m2m_fields=None):
|
|||||||
else:
|
else:
|
||||||
array[key] = cell_value
|
array[key] = cell_value
|
||||||
tables.append(array)
|
tables.append(array)
|
||||||
return tables
|
data = [i for i in tables if len(i) != 0]
|
||||||
|
return data
|
||||||
|
|||||||
@@ -2,6 +2,9 @@ import { defineStore } from 'pinia';
|
|||||||
import { UserInfosStates } from './interface';
|
import { UserInfosStates } from './interface';
|
||||||
import { Session } from '/@/utils/storage';
|
import { Session } from '/@/utils/storage';
|
||||||
import { request } from '../utils/service';
|
import { request } from '../utils/service';
|
||||||
|
import { getBaseURL } from '../utils/baseUrl';
|
||||||
|
import headerImage from '/@/assets/img/headerImage.png';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 用户信息
|
* 用户信息
|
||||||
* @methods setUserInfos 设置用户信息
|
* @methods setUserInfos 设置用户信息
|
||||||
@@ -72,7 +75,7 @@ export const useUserInfo = defineStore('userInfo', {
|
|||||||
method: 'get',
|
method: 'get',
|
||||||
}).then((res:any)=>{
|
}).then((res:any)=>{
|
||||||
this.userInfos.username = res.data.name;
|
this.userInfos.username = res.data.name;
|
||||||
this.userInfos.avatar = res.data.avatar;
|
this.userInfos.avatar = (res.data.avatar && getBaseURL(res.data.avatar)) || headerImage;
|
||||||
this.userInfos.name = res.data.name;
|
this.userInfos.name = res.data.name;
|
||||||
this.userInfos.email = res.data.email;
|
this.userInfos.email = res.data.email;
|
||||||
this.userInfos.mobile = res.data.mobile;
|
this.userInfos.mobile = res.data.mobile;
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import XEUtils from 'xe-utils';
|
||||||
import {useColumnPermission} from '/@/stores/columnPermission';
|
import {useColumnPermission} from '/@/stores/columnPermission';
|
||||||
|
|
||||||
type permissionType = 'is_create' | 'is_query' | 'is_update';
|
type permissionType = 'is_create' | 'is_query' | 'is_update';
|
||||||
@@ -23,25 +24,17 @@ export const handleColumnPermission = async (func: Function, crudOptions: any,ex
|
|||||||
}
|
}
|
||||||
const columns = crudOptions.columns;
|
const columns = crudOptions.columns;
|
||||||
const excludeColumns = ['checked','_index','id', 'create_datetime', 'update_datetime'].concat(excludeColumn)
|
const excludeColumns = ['checked','_index','id', 'create_datetime', 'update_datetime'].concat(excludeColumn)
|
||||||
for (let col in columns) {
|
XEUtils.eachTree(columns, (item, key) => {
|
||||||
for (let item of res.data) {
|
if (!excludeColumns.includes(String(key)) && key in res.data) {
|
||||||
if (excludeColumns.includes(item.field_name)) {
|
// 如果列表不可见,则禁止在列设置中选择
|
||||||
continue
|
// 只有列表不可见,才修改列配置,这样才不影响默认的配置
|
||||||
} else if(item.field_name === col) {
|
if (!res.data[key]['is_query']) {
|
||||||
// 如果列表不可见,则禁止在列设置中选择
|
item.column.show = false;
|
||||||
// 只有列表不可见,才修改列配置,这样才不影响默认的配置
|
item.column.columnSetDisabled = true;
|
||||||
if(!item['is_query']){
|
|
||||||
columns[col].column.show = false
|
|
||||||
columns[col].column.columnSetDisabled = true
|
|
||||||
}
|
|
||||||
columns[col].addForm = {
|
|
||||||
show: item['is_create']
|
|
||||||
}
|
|
||||||
columns[col].editForm = {
|
|
||||||
show: item['is_update']
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
item.addForm = { show: res.data[key]['is_create'] };
|
||||||
|
item.editForm = { show: res.data[key]['is_update'] };
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
return crudOptions
|
return crudOptions
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -260,10 +260,10 @@ export const createCrudOptions = function ({ crudExpose, context }: CreateCrudOp
|
|||||||
}),
|
}),
|
||||||
column: {
|
column: {
|
||||||
minWidth: 200, //最小列宽
|
minWidth: 200, //最小列宽
|
||||||
formatter({ value, row, index }) {
|
// formatter({ value, row, index }) {
|
||||||
const values = row.role_info.map((item: any) => item.name);
|
// const values = row.role_info.map((item: any) => item.name);
|
||||||
return values.join(',')
|
// return values.join(',')
|
||||||
}
|
// }
|
||||||
},
|
},
|
||||||
form: {
|
form: {
|
||||||
rules: [
|
rules: [
|
||||||
@@ -382,12 +382,12 @@ export const createCrudOptions = function ({ crudExpose, context }: CreateCrudOp
|
|||||||
},
|
},
|
||||||
avatar: {
|
avatar: {
|
||||||
title: '头像',
|
title: '头像',
|
||||||
type: 'avatar-cropper',
|
type: 'avatar-uploader',
|
||||||
form: {
|
form: {
|
||||||
show: false,
|
show: false,
|
||||||
},
|
},
|
||||||
column: {
|
column: {
|
||||||
width: 150,
|
width: 100,
|
||||||
showOverflowTooltip: true,
|
showOverflowTooltip: true,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -42,6 +42,15 @@
|
|||||||
<template #actionbar-right>
|
<template #actionbar-right>
|
||||||
<importExcel api="api/system/user/" v-auth="'user:Import'">导入 </importExcel>
|
<importExcel api="api/system/user/" v-auth="'user:Import'">导入 </importExcel>
|
||||||
</template>
|
</template>
|
||||||
|
<template #cell_avatar="scope">
|
||||||
|
<div v-if="scope.row.avatar" style="display: flex; justify-content: center; align-items: center;">
|
||||||
|
<el-image
|
||||||
|
style="width: 50px; height: 50px; border-radius: 50%; aspect-ratio: 1 /1 ; "
|
||||||
|
:src="getBaseURL(scope.row.avatar)"
|
||||||
|
:preview-src-list="[getBaseURL(scope.row.avatar)]"
|
||||||
|
:preview-teleported="true" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
</fs-crud>
|
</fs-crud>
|
||||||
|
|
||||||
<el-dialog v-model="resetPwdVisible" title="重设密码" width="400px" draggable :before-close="handleResetPwdClose">
|
<el-dialog v-model="resetPwdVisible" title="重设密码" width="400px" draggable :before-close="handleResetPwdClose">
|
||||||
@@ -69,6 +78,7 @@ import { ECharts, EChartsOption, init } from 'echarts';
|
|||||||
import { getDeptInfoById, resetPwd } from './api';
|
import { getDeptInfoById, resetPwd } from './api';
|
||||||
import { warningNotification, successNotification } from '/@/utils/message';
|
import { warningNotification, successNotification } from '/@/utils/message';
|
||||||
import { HeadDeptInfoType } from '../../types';
|
import { HeadDeptInfoType } from '../../types';
|
||||||
|
import {getBaseURL} from '/@/utils/baseUrl';
|
||||||
|
|
||||||
let deptCountChart: ECharts;
|
let deptCountChart: ECharts;
|
||||||
let deptSexChart: ECharts;
|
let deptSexChart: ECharts;
|
||||||
|
|||||||
@@ -32,7 +32,7 @@
|
|||||||
<el-col :xs="24" :sm="24" class="personal-item mb6">
|
<el-col :xs="24" :sm="24" class="personal-item mb6">
|
||||||
<div class="personal-item-label">角色:</div>
|
<div class="personal-item-label">角色:</div>
|
||||||
<div class="personal-item-value">
|
<div class="personal-item-value">
|
||||||
<el-tag v-for="(item, index) in state.personalForm.role_info" :key="index">{{ item.name }}</el-tag>
|
<el-tag v-for="(item, index) in state.personalForm.role_info" :key="index" style="margin-right: 5px;">{{ item.name }}</el-tag>
|
||||||
</div>
|
</div>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
|||||||
@@ -1,70 +0,0 @@
|
|||||||
import { request } from "/@/utils/service";
|
|
||||||
import XEUtils from "xe-utils";
|
|
||||||
/**
|
|
||||||
* 获取角色的授权列表
|
|
||||||
* @param roleId
|
|
||||||
* @param query
|
|
||||||
*/
|
|
||||||
export function getRolePermission(query:object) {
|
|
||||||
return request({
|
|
||||||
url: '/api/system/role_menu_button_permission/get_role_permission/',
|
|
||||||
method: 'get',
|
|
||||||
params:query
|
|
||||||
}).then((res:any)=>{
|
|
||||||
return XEUtils.toArrayTree(res.data, {key: 'id', parentKey: 'parent',children: 'children',strict: false})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/***
|
|
||||||
* 设置角色的权限
|
|
||||||
* @param roleId
|
|
||||||
* @param data
|
|
||||||
*/
|
|
||||||
export function setRolePremission(roleId:any,data:object) {
|
|
||||||
return request({
|
|
||||||
url: `/api/system/role_menu_button_permission/${roleId}/set_role_premission/`,
|
|
||||||
method: 'put',
|
|
||||||
data
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getDataPermissionRange(query:object) {
|
|
||||||
return request({
|
|
||||||
url: '/api/system/role_menu_button_permission/data_scope/',
|
|
||||||
method: 'get',
|
|
||||||
params:query
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getDataPermissionRangeAll() {
|
|
||||||
return request({
|
|
||||||
url: '/api/system/role_menu_button_permission/data_scope/',
|
|
||||||
method: 'get',
|
|
||||||
})
|
|
||||||
}
|
|
||||||
export function getDataPermissionDept(query:object) {
|
|
||||||
return request({
|
|
||||||
url: '/api/system/role_menu_button_permission/role_to_dept_all/',
|
|
||||||
method: 'get',
|
|
||||||
params:query
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getDataPermissionMenu() {
|
|
||||||
return request({
|
|
||||||
url: '/api/system/role_menu_button_permission/get_role_permissions/',
|
|
||||||
method: 'get'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置按钮的数据范围
|
|
||||||
*/
|
|
||||||
export function setBtnDatarange(roleId:number,data:object) {
|
|
||||||
return request({
|
|
||||||
url: `/api/system/role_menu_button_permission/${roleId}/set_btn_datarange/`,
|
|
||||||
method: 'put',
|
|
||||||
data
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,451 +0,0 @@
|
|||||||
<template>
|
|
||||||
<el-drawer
|
|
||||||
v-model="drawerVisibleNew"
|
|
||||||
title="权限配置"
|
|
||||||
direction="rtl"
|
|
||||||
size="60%"
|
|
||||||
:close-on-click-modal="false"
|
|
||||||
:before-close="handleDrawerClose"
|
|
||||||
:destroy-on-close="true"
|
|
||||||
>
|
|
||||||
<template #header>
|
|
||||||
<el-row>
|
|
||||||
<el-col :span="4">
|
|
||||||
<div>
|
|
||||||
当前授权角色:
|
|
||||||
<el-tag>{{ props.roleName }}</el-tag>
|
|
||||||
</div>
|
|
||||||
</el-col>
|
|
||||||
<el-col :span="6">
|
|
||||||
<div>
|
|
||||||
<el-button size="small" type="primary" class="pc-save-btn" @click="handleSavePermission">保存菜单授权 </el-button>
|
|
||||||
</div>
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
</template>
|
|
||||||
<div class="permission-com">
|
|
||||||
<el-row class="menu-el-row" :gutter="20">
|
|
||||||
<el-col :span="6">
|
|
||||||
<div class="menu-box menu-left-box">
|
|
||||||
<el-tree
|
|
||||||
ref="treeRef"
|
|
||||||
:data="menuData"
|
|
||||||
:props="defaultTreeProps"
|
|
||||||
:default-checked-keys="menuDefaultCheckedKeys"
|
|
||||||
@check="handleMenuCheck"
|
|
||||||
@node-click="handleMenuClick"
|
|
||||||
node-key="id"
|
|
||||||
check-strictly
|
|
||||||
highlight-current
|
|
||||||
show-checkbox
|
|
||||||
default-expand-all
|
|
||||||
>
|
|
||||||
</el-tree>
|
|
||||||
</div>
|
|
||||||
</el-col>
|
|
||||||
|
|
||||||
<el-col :span="18">
|
|
||||||
<div class="pc-collapse-main" v-if="menuCurrent.btns && menuCurrent.btns.length > 0">
|
|
||||||
<div class="pccm-item">
|
|
||||||
<div class="menu-form-alert">配置操作功能接口权限,配置数据权限点击小齿轮</div>
|
|
||||||
<el-checkbox v-for="(btn, bIndex) in menuCurrent.btns" :key="bIndex" v-model="btn.isCheck" :label="btn.value">
|
|
||||||
<div class="btn-item">
|
|
||||||
{{ btn.data_range !== null ? `${btn.name}(${formatDataRange(btn.data_range)})` : btn.name }}
|
|
||||||
<span v-show="btn.isCheck" @click.stop.prevent="handleSettingClick(menuCurrent, btn)">
|
|
||||||
<el-icon>
|
|
||||||
<Setting />
|
|
||||||
</el-icon>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</el-checkbox>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="pccm-item" v-if="menuCurrent.columns && menuCurrent.columns.length > 0">
|
|
||||||
<div class="menu-form-alert">配置数据列字段权限</div>
|
|
||||||
<ul class="columns-list">
|
|
||||||
<li class="columns-head">
|
|
||||||
<div class="width-txt">
|
|
||||||
<span>字段</span>
|
|
||||||
</div>
|
|
||||||
<div v-for="(head, hIndex) in column.header" :key="hIndex" class="width-check">
|
|
||||||
<el-checkbox :label="head.value" @change="handleColumnChange($event, menuCurrent, head.value, head.disabled)">
|
|
||||||
<span>{{ head.label }}</span>
|
|
||||||
</el-checkbox>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li v-for="(c_item, c_index) in menuCurrent.columns" :key="c_index" class="columns-item">
|
|
||||||
<div class="width-txt">{{ c_item.title }}</div>
|
|
||||||
<div v-for="(col, cIndex) in column.header" :key="cIndex" class="width-check">
|
|
||||||
<el-checkbox v-model="c_item[col.value]" class="ci-checkout" :disabled="c_item[col.disabled]"></el-checkbox>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
|
|
||||||
<el-dialog v-model="dialogVisible" title="数据权限配置" width="400px" :close-on-click-modal="false" :before-close="handleDialogClose">
|
|
||||||
<div class="pc-dialog">
|
|
||||||
<el-select v-model="dataPermission" @change="handlePermissionRangeChange" class="dialog-select" placeholder="请选择">
|
|
||||||
<el-option v-for="item in dataPermissionRange" :key="item.value" :label="item.label" :value="item.value" />
|
|
||||||
</el-select>
|
|
||||||
<el-tree-select
|
|
||||||
v-show="dataPermission === 4"
|
|
||||||
node-key="id"
|
|
||||||
v-model="customDataPermission"
|
|
||||||
:props="defaultTreeProps"
|
|
||||||
:data="deptData"
|
|
||||||
multiple
|
|
||||||
check-strictly
|
|
||||||
:render-after-expand="false"
|
|
||||||
show-checkbox
|
|
||||||
class="dialog-tree"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<template #footer>
|
|
||||||
<div>
|
|
||||||
<el-button type="primary" @click="handleDialogConfirm"> 确定</el-button>
|
|
||||||
<el-button @click="handleDialogClose"> 取消</el-button>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</el-dialog>
|
|
||||||
</div>
|
|
||||||
</el-drawer>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
import { ref, onMounted, defineProps, watch, computed, reactive } from 'vue';
|
|
||||||
import XEUtils from 'xe-utils';
|
|
||||||
import { errorNotification } from '/@/utils/message';
|
|
||||||
import { getDataPermissionRange, getDataPermissionDept, getRolePermission, setRolePremission, setBtnDatarange } from './api';
|
|
||||||
import { MenuDataType, DataPermissionRangeType, CustomDataPermissionDeptType } from './types';
|
|
||||||
import { ElMessage, ElTree } from 'element-plus';
|
|
||||||
|
|
||||||
|
|
||||||
const props = defineProps({
|
|
||||||
roleId: {
|
|
||||||
type: Number,
|
|
||||||
default: -1,
|
|
||||||
},
|
|
||||||
roleName: {
|
|
||||||
type: String,
|
|
||||||
default: '',
|
|
||||||
},
|
|
||||||
drawerVisible: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
const emit = defineEmits(['update:drawerVisible']);
|
|
||||||
|
|
||||||
const drawerVisibleNew = ref(false);
|
|
||||||
watch(
|
|
||||||
() => props.drawerVisible,
|
|
||||||
(val) => {
|
|
||||||
drawerVisibleNew .value = val;
|
|
||||||
getMenuBtnPermission();
|
|
||||||
getDataPermissionRangeLable();
|
|
||||||
menuCurrent.value = {};
|
|
||||||
}
|
|
||||||
);
|
|
||||||
const handleDrawerClose = () => {
|
|
||||||
emit('update:drawerVisible', false);
|
|
||||||
};
|
|
||||||
|
|
||||||
const defaultTreeProps = {
|
|
||||||
children: 'children',
|
|
||||||
label: 'name',
|
|
||||||
value: 'id',
|
|
||||||
};
|
|
||||||
|
|
||||||
let menuData = ref<MenuDataType[]>([]); // 菜单列表数据
|
|
||||||
let menuDefaultCheckedKeys = ref<number[]>([]); // 默认选中的菜单列表
|
|
||||||
let menuCurrent = ref<Partial<MenuDataType>>({}); // 当前选中的菜单
|
|
||||||
|
|
||||||
let menuBtnCurrent = ref<number>(-1);
|
|
||||||
let dialogVisible = ref(false);
|
|
||||||
let dataPermissionRange = ref<DataPermissionRangeType[]>([]);
|
|
||||||
let dataPermissionRangeLabel = ref<DataPermissionRangeType[]>([]);
|
|
||||||
|
|
||||||
const formatDataRange = computed(() => {
|
|
||||||
return function (datarange: number) {
|
|
||||||
const findItem = dataPermissionRangeLabel.value.find((i) => i.value === datarange);
|
|
||||||
return findItem?.label || '';
|
|
||||||
};
|
|
||||||
});
|
|
||||||
let deptData = ref<CustomDataPermissionDeptType[]>([]);
|
|
||||||
let dataPermission = ref();
|
|
||||||
let customDataPermission = ref([]);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 菜单复选框选中
|
|
||||||
* @param node
|
|
||||||
* @param data
|
|
||||||
*/
|
|
||||||
const handleMenuCheck = (node: any, data: any) => {
|
|
||||||
XEUtils.eachTree(menuData.value, (item) => {
|
|
||||||
item.isCheck = data.checkedKeys.includes(item.id);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
/**
|
|
||||||
* 菜单点击
|
|
||||||
* @param node
|
|
||||||
* @param data
|
|
||||||
*/
|
|
||||||
const handleMenuClick = (selectNode: MenuDataType) => {
|
|
||||||
menuCurrent.value = selectNode;
|
|
||||||
};
|
|
||||||
//获取菜单,按钮,权限
|
|
||||||
const getMenuBtnPermission = async () => {
|
|
||||||
const resMenu = await getRolePermission({ role: props.roleId });
|
|
||||||
menuData.value = resMenu;
|
|
||||||
menuDefaultCheckedKeys.value = XEUtils.toTreeArray(resMenu)
|
|
||||||
.filter((i) => i.isCheck)
|
|
||||||
.map((i) => i.id);
|
|
||||||
};
|
|
||||||
// 获取按钮的数据权限下拉选项
|
|
||||||
const getDataPermissionRangeLable = async () => {
|
|
||||||
const resRange = await getDataPermissionRange({ role: props.roleId });
|
|
||||||
dataPermissionRangeLabel.value = resRange.data;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取按钮数据权限下拉选项
|
|
||||||
* @param btnId 按钮id
|
|
||||||
*/
|
|
||||||
const fetchData = async (btnId: number) => {
|
|
||||||
try {
|
|
||||||
const resRange = await getDataPermissionRange({ menu_button: btnId });
|
|
||||||
if (resRange?.code === 2000) {
|
|
||||||
dataPermissionRange.value = resRange.data;
|
|
||||||
}
|
|
||||||
} catch {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置按钮数据权限
|
|
||||||
* @param record 当前菜单
|
|
||||||
* @param btnType 按钮类型
|
|
||||||
*/
|
|
||||||
const handleSettingClick = (record: any, btn: MenuDataType['btns'][number]) => {
|
|
||||||
menuCurrent.value = record;
|
|
||||||
menuBtnCurrent.value = btn.id;
|
|
||||||
dialogVisible.value = true;
|
|
||||||
dataPermission.value = btn.data_range;
|
|
||||||
handlePermissionRangeChange(btn.data_range);
|
|
||||||
fetchData(btn.id);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置列权限
|
|
||||||
* @param val 是否选中
|
|
||||||
* @param record 当前菜单
|
|
||||||
* @param btnType 按钮类型
|
|
||||||
* @param disabledType 禁用类型
|
|
||||||
*/
|
|
||||||
const handleColumnChange = (val: boolean, record: any, btnType: string, disabledType: string) => {
|
|
||||||
for (const iterator of record.columns) {
|
|
||||||
iterator[btnType] = iterator[disabledType] ? iterator[btnType] : val;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 数据权限设置
|
|
||||||
*/
|
|
||||||
const handlePermissionRangeChange = async (val: number) => {
|
|
||||||
if (val === 4) {
|
|
||||||
const res = await getDataPermissionDept({ role: props.roleId, menu_button: menuBtnCurrent.value });
|
|
||||||
const depts = XEUtils.toArrayTree(res.data, { parentKey: 'parent', strict: false });
|
|
||||||
deptData.value = depts;
|
|
||||||
const btnObj = XEUtils.find(menuCurrent.value.btns, (item) => item.id === menuBtnCurrent.value);
|
|
||||||
customDataPermission.value = btnObj.dept;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 数据权限设置确认
|
|
||||||
*/
|
|
||||||
const handleDialogConfirm = () => {
|
|
||||||
if (dataPermission.value !== 0 && !dataPermission.value) {
|
|
||||||
errorNotification('请选择');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (const btn of menuCurrent.value?.btns || []) {
|
|
||||||
if (btn.id === menuBtnCurrent.value) {
|
|
||||||
const findItem = dataPermissionRange.value.find((i) => i.value === dataPermission.value);
|
|
||||||
btn.data_range = findItem?.value || 0;
|
|
||||||
if (btn.data_range === 4) {
|
|
||||||
btn.dept = customDataPermission.value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
handleDialogClose();
|
|
||||||
};
|
|
||||||
const handleDialogClose = () => {
|
|
||||||
dialogVisible.value = false;
|
|
||||||
customDataPermission.value = [];
|
|
||||||
dataPermission.value = null;
|
|
||||||
};
|
|
||||||
|
|
||||||
//保存菜单授权
|
|
||||||
const handleSavePermission = () => {
|
|
||||||
setRolePremission(props.roleId, XEUtils.toTreeArray(menuData.value)).then((res: any) => {
|
|
||||||
ElMessage({
|
|
||||||
message: res.msg,
|
|
||||||
type: 'success',
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const column = reactive({
|
|
||||||
header: [
|
|
||||||
{ value: 'is_create', label: '新增可见', disabled: 'disabled_create' },
|
|
||||||
{ value: 'is_update', label: '编辑可见', disabled: 'disabled_update' },
|
|
||||||
{ value: 'is_query', label: '列表可见', disabled: 'disabled_query' },
|
|
||||||
],
|
|
||||||
});
|
|
||||||
|
|
||||||
onMounted(() => {});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.permission-com {
|
|
||||||
margin: 15px;
|
|
||||||
box-sizing: border-box;
|
|
||||||
|
|
||||||
.pc-save-btn {
|
|
||||||
margin-bottom: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.pc-collapse-title {
|
|
||||||
line-height: 32px;
|
|
||||||
text-align: left;
|
|
||||||
|
|
||||||
span {
|
|
||||||
font-size: 16px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.pc-collapse-main {
|
|
||||||
box-sizing: border-box;
|
|
||||||
|
|
||||||
.pccm-item {
|
|
||||||
margin-bottom: 10px;
|
|
||||||
|
|
||||||
.menu-form-alert {
|
|
||||||
color: #fff;
|
|
||||||
line-height: 24px;
|
|
||||||
padding: 8px 16px;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
border-radius: 4px;
|
|
||||||
background-color: var(--el-color-primary);
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-item {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
span {
|
|
||||||
margin-left: 5px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.columns-list {
|
|
||||||
.width-txt {
|
|
||||||
width: 200px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.width-check {
|
|
||||||
width: 100px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.width-icon {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.columns-head {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
padding: 6px 0;
|
|
||||||
border-bottom: 1px solid #ebeef5;
|
|
||||||
box-sizing: border-box;
|
|
||||||
|
|
||||||
span {
|
|
||||||
font-weight: 900;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.columns-item {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
padding: 6px 0;
|
|
||||||
box-sizing: border-box;
|
|
||||||
|
|
||||||
.ci-checkout {
|
|
||||||
height: auto !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.pc-dialog {
|
|
||||||
.dialog-select {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dialog-tree {
|
|
||||||
width: 100%;
|
|
||||||
margin-top: 20px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
.permission-com {
|
|
||||||
.el-collapse {
|
|
||||||
border-top: none;
|
|
||||||
border-bottom: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.el-collapse-item {
|
|
||||||
margin-bottom: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.el-collapse-item__header {
|
|
||||||
height: auto;
|
|
||||||
padding: 15px;
|
|
||||||
border-radius: 8px;
|
|
||||||
border-top: 1px solid #ebeef5;
|
|
||||||
border-left: 1px solid #ebeef5;
|
|
||||||
border-right: 1px solid #ebeef5;
|
|
||||||
box-sizing: border-box;
|
|
||||||
background-color: #fafafa;
|
|
||||||
}
|
|
||||||
|
|
||||||
.el-collapse-item__header.is-active {
|
|
||||||
border-radius: 8px 8px 0 0;
|
|
||||||
background-color: #fafafa;
|
|
||||||
}
|
|
||||||
|
|
||||||
.el-collapse-item__wrap {
|
|
||||||
padding: 15px;
|
|
||||||
border-left: 1px solid #ebeef5;
|
|
||||||
border-right: 1px solid #ebeef5;
|
|
||||||
border-top: 1px solid #ebeef5;
|
|
||||||
border-radius: 0 0 8px 8px;
|
|
||||||
background-color: #fafafa;
|
|
||||||
box-sizing: border-box;
|
|
||||||
|
|
||||||
.el-collapse-item__content {
|
|
||||||
padding-bottom: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
export interface DataPermissionRangeType {
|
|
||||||
label: string;
|
|
||||||
value: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface CustomDataPermissionDeptType {
|
|
||||||
id: number;
|
|
||||||
name: string;
|
|
||||||
patent: number;
|
|
||||||
children: CustomDataPermissionDeptType[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface CustomDataPermissionMenuType {
|
|
||||||
id: number;
|
|
||||||
name: string;
|
|
||||||
is_catalog: boolean;
|
|
||||||
menuPermission: { id: number; name: string; value: string }[] | null;
|
|
||||||
columns: { id: number; name: string; title: string }[] | null;
|
|
||||||
children: CustomDataPermissionMenuType[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface MenuDataType {
|
|
||||||
id: string;
|
|
||||||
name: string;
|
|
||||||
isCheck: boolean;
|
|
||||||
btns: { id: number; name: string; value: string; isCheck: boolean; data_range: number; dept: object }[];
|
|
||||||
columns: { [key: string]: boolean | string; }[];
|
|
||||||
children: MenuDataType[];
|
|
||||||
}
|
|
||||||
76
web/src/views/system/role/components/RoleDrawer.vue
Normal file
76
web/src/views/system/role/components/RoleDrawer.vue
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
<template>
|
||||||
|
<el-drawer
|
||||||
|
v-model="RoleDrawer.drawerVisible"
|
||||||
|
title="权限配置"
|
||||||
|
direction="rtl"
|
||||||
|
size="80%"
|
||||||
|
:close-on-click-modal="false"
|
||||||
|
:before-close="RoleDrawer.handleDrawerClose"
|
||||||
|
:destroy-on-close="true"
|
||||||
|
>
|
||||||
|
<template #header>
|
||||||
|
<div>
|
||||||
|
当前授权角色:
|
||||||
|
<el-tag style="margin-right: 20px">{{ RoleDrawer.roleName }}</el-tag>
|
||||||
|
授权人员:
|
||||||
|
<el-button size="small" :icon="UserFilled" @click="handleUsers">{{ RoleDrawer.users.length }}</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<splitpanes class="default-theme" style="height: 100%">
|
||||||
|
<pane min-size="20" size="22">
|
||||||
|
<div class="pane-box">
|
||||||
|
<MenuTreeCom />
|
||||||
|
</div>
|
||||||
|
</pane>
|
||||||
|
<pane min-size="20">
|
||||||
|
<div class="pane-box">
|
||||||
|
<el-tabs v-model="activeName" class="demo-tabs">
|
||||||
|
<el-tab-pane label="接口权限" name="first"><MenuBtnCom /></el-tab-pane>
|
||||||
|
<el-tab-pane label="列字段权限" name="second"><MenuFieldCom /></el-tab-pane>
|
||||||
|
</el-tabs>
|
||||||
|
</div>
|
||||||
|
</pane>
|
||||||
|
</splitpanes>
|
||||||
|
</el-drawer>
|
||||||
|
|
||||||
|
<el-dialog v-model="dialogVisible" title="授权用户" width="700px" :close-on-click-modal="false">
|
||||||
|
<RoleUsersCom />
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { Splitpanes, Pane } from 'splitpanes';
|
||||||
|
import 'splitpanes/dist/splitpanes.css';
|
||||||
|
import { UserFilled } from '@element-plus/icons-vue';
|
||||||
|
import { RoleDrawerStores } from '../stores/RoleDrawerStores';
|
||||||
|
import { defineAsyncComponent, ref } from 'vue';
|
||||||
|
import { RoleUsersStores } from '../stores/RoleUsersStores';
|
||||||
|
|
||||||
|
const MenuTreeCom = defineAsyncComponent(() => import('./RoleMenuTree.vue'));
|
||||||
|
const MenuBtnCom = defineAsyncComponent(() => import('./RoleMenuBtn.vue'));
|
||||||
|
const MenuFieldCom = defineAsyncComponent(() => import('./RoleMenuField.vue'));
|
||||||
|
const RoleUsersCom = defineAsyncComponent(() => import('./RoleUsers.vue'));
|
||||||
|
const RoleDrawer = RoleDrawerStores(); // 抽屉参数
|
||||||
|
const RoleUsers = RoleUsersStores(); // 角色-用户
|
||||||
|
const activeName = ref('first');
|
||||||
|
|
||||||
|
const dialogVisible = ref(false);
|
||||||
|
|
||||||
|
const handleUsers = () => {
|
||||||
|
dialogVisible.value = true;
|
||||||
|
RoleUsers.get_all_users(); // 获取所有用户
|
||||||
|
RoleUsers.set_right_users(RoleDrawer.$state.users); // 设置已选中用户
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.pane-box {
|
||||||
|
width: 100vw; /* 视口宽度 */
|
||||||
|
height: 100vh; /* 视口高度 */
|
||||||
|
max-width: 100%; /* 确保不超过父元素的宽度 */
|
||||||
|
max-height: 100%; /* 确保不超过父元素的高度 */
|
||||||
|
overflow: auto; /* 当内容超出容器尺寸时显示滚动条 */
|
||||||
|
padding: 10px;
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
186
web/src/views/system/role/components/RoleMenuBtn.vue
Normal file
186
web/src/views/system/role/components/RoleMenuBtn.vue
Normal file
@@ -0,0 +1,186 @@
|
|||||||
|
<template>
|
||||||
|
<div class="pccm-item" v-if="RoleMenuBtn.$state.length > 0">
|
||||||
|
<div class="menu-form-alert">配置操作功能接口权限,配置数据权限点击小齿轮</div>
|
||||||
|
<el-checkbox v-for="btn in RoleMenuBtn.$state" :key="btn.id" v-model="btn.isCheck" @change="handleCheckChange(btn)">
|
||||||
|
<div class="btn-item">
|
||||||
|
{{ btn.data_range !== null ? `${btn.name}(${formatDataRange(btn.data_range)})` : btn.name }}
|
||||||
|
<span v-show="btn.isCheck" @click.stop.prevent="handleSettingClick(btn)">
|
||||||
|
<el-icon>
|
||||||
|
<Setting />
|
||||||
|
</el-icon>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</el-checkbox>
|
||||||
|
</div>
|
||||||
|
<el-dialog v-model="dialogVisible" title="数据权限配置" width="400px" :close-on-click-modal="false" :before-close="handleDialogClose">
|
||||||
|
<div class="pc-dialog">
|
||||||
|
<el-select v-model="selectBtn.data_range" @change="handlePermissionRangeChange" placeholder="请选择">
|
||||||
|
<el-option v-for="item in dataPermissionRange" :key="item.value" :label="item.label" :value="item.value" />
|
||||||
|
</el-select>
|
||||||
|
<el-tree-select
|
||||||
|
v-show="selectBtn.data_range === 4"
|
||||||
|
node-key="id"
|
||||||
|
v-model="selectBtn.dept"
|
||||||
|
:props="defaultTreeProps"
|
||||||
|
:data="deptData"
|
||||||
|
multiple
|
||||||
|
check-strictly
|
||||||
|
:render-after-expand="false"
|
||||||
|
show-checkbox
|
||||||
|
class="dialog-tree"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<template #footer>
|
||||||
|
<div>
|
||||||
|
<el-button type="primary" @click="handleDialogConfirm"> 确定</el-button>
|
||||||
|
<el-button @click="handleDialogClose"> 取消</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { computed, onMounted, ref } from 'vue';
|
||||||
|
import { RoleDrawerStores } from '../stores/RoleDrawerStores';
|
||||||
|
import { RoleMenuBtnStores } from '../stores/RoleMenuBtnStores';
|
||||||
|
import { RoleMenuTreeStores } from '../stores/RoleMenuTreeStores';
|
||||||
|
import { RoleMenuBtnType } from '../types';
|
||||||
|
import { getRoleToDeptAll, setRoleMenuBtn, setRoleMenuBtnDataRange } from './api';
|
||||||
|
import XEUtils from 'xe-utils';
|
||||||
|
import { ElMessage } from 'element-plus';
|
||||||
|
const RoleDrawer = RoleDrawerStores(); // 角色-菜单
|
||||||
|
const RoleMenuTree = RoleMenuTreeStores(); // 角色-菜单
|
||||||
|
const RoleMenuBtn = RoleMenuBtnStores(); // 角色-菜单-按钮
|
||||||
|
const dialogVisible = ref(false);
|
||||||
|
// 选中的按钮
|
||||||
|
const selectBtn = ref<RoleMenuBtnType>({
|
||||||
|
id: 0,
|
||||||
|
menu_btn_pre_id: 0,
|
||||||
|
/** 是否选中 */
|
||||||
|
isCheck: false,
|
||||||
|
/** 按钮名称 */
|
||||||
|
name: '',
|
||||||
|
/** 数据权限范围 */
|
||||||
|
data_range: 0,
|
||||||
|
dept: [],
|
||||||
|
});
|
||||||
|
/**
|
||||||
|
* 数据权限范围
|
||||||
|
*/
|
||||||
|
const dataPermissionRange = ref([
|
||||||
|
{ label: '仅本人数据权限', value: 0 },
|
||||||
|
{ label: '本部门及以下数据权限', value: 1 },
|
||||||
|
{ label: '本部门数据权限', value: 2 },
|
||||||
|
{ label: '全部数据权限', value: 3 },
|
||||||
|
{ label: '自定数据权限', value: 4 },
|
||||||
|
]);
|
||||||
|
/**
|
||||||
|
* 自定义数据权限的部门树配置
|
||||||
|
*/
|
||||||
|
const defaultTreeProps = {
|
||||||
|
children: 'children',
|
||||||
|
label: 'name',
|
||||||
|
value: 'id',
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自定数据权限下拉选择事件
|
||||||
|
*/
|
||||||
|
const handlePermissionRangeChange = async (val: number) => {
|
||||||
|
if (val < 4) {
|
||||||
|
selectBtn.value.dept = [];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* 格式化按钮数据范围
|
||||||
|
*/
|
||||||
|
const formatDataRange = computed(() => {
|
||||||
|
return function (datarange: number) {
|
||||||
|
const datarangeitem = XEUtils.find(dataPermissionRange.value, (item: any) => {
|
||||||
|
if (item.value === datarange) {
|
||||||
|
return item.label;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return datarangeitem.label;
|
||||||
|
};
|
||||||
|
});
|
||||||
|
/**
|
||||||
|
* 勾选按钮
|
||||||
|
*/
|
||||||
|
const handleCheckChange = async (btn: RoleMenuBtnType) => {
|
||||||
|
const put_data = {
|
||||||
|
isCheck: btn.isCheck,
|
||||||
|
roleId: RoleDrawer.roleId,
|
||||||
|
menuId: RoleMenuTree.id,
|
||||||
|
btnId: btn.id,
|
||||||
|
};
|
||||||
|
const { data, msg } = await setRoleMenuBtn(put_data);
|
||||||
|
RoleMenuBtn.updateState(data);
|
||||||
|
ElMessage({ message: msg, type: 'success' });
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按钮-数据范围确定
|
||||||
|
*/
|
||||||
|
const handleDialogConfirm = async () => {
|
||||||
|
const { data, msg } = await setRoleMenuBtnDataRange(selectBtn.value);
|
||||||
|
selectBtn.value = data;
|
||||||
|
dialogVisible.value = false;
|
||||||
|
ElMessage({ message: msg, type: 'success' });
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* 数据范围关闭
|
||||||
|
*/
|
||||||
|
const handleDialogClose = () => {
|
||||||
|
dialogVisible.value = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 齿轮点击
|
||||||
|
*/
|
||||||
|
const handleSettingClick = async (btn: RoleMenuBtnType) => {
|
||||||
|
selectBtn.value = btn;
|
||||||
|
dialogVisible.value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 部门数据
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
const deptData = ref<number[]>([]);
|
||||||
|
// 页面打开后获取列表数据
|
||||||
|
onMounted(async () => {
|
||||||
|
const res = await getRoleToDeptAll({ role: RoleDrawer.roleId, menu_button: selectBtn.value.id });
|
||||||
|
const depts = XEUtils.toArrayTree(res.data, { parentKey: 'parent', strict: false });
|
||||||
|
deptData.value = depts;
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.pccm-item {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
.menu-form-alert {
|
||||||
|
color: #fff;
|
||||||
|
line-height: 24px;
|
||||||
|
padding: 8px 16px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
border-radius: 4px;
|
||||||
|
background-color: var(--el-color-primary);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// .el-checkbox {
|
||||||
|
// width: 200px;
|
||||||
|
// }
|
||||||
|
.btn-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center; /* 水平居中 */
|
||||||
|
.el-icon {
|
||||||
|
margin-left: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.dialog-tree {
|
||||||
|
width: 100%;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
118
web/src/views/system/role/components/RoleMenuField.vue
Normal file
118
web/src/views/system/role/components/RoleMenuField.vue
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
<template>
|
||||||
|
<div class="pccm-item" v-if="RoleMenuField.$state.length > 0">
|
||||||
|
<div class="menu-form-alert">
|
||||||
|
<el-button size="small" @click="handleSaveField">保存 </el-button>
|
||||||
|
配置数据列字段权限
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ul class="columns-list">
|
||||||
|
<li class="columns-head">
|
||||||
|
<div class="width-txt">
|
||||||
|
<span>字段</span>
|
||||||
|
</div>
|
||||||
|
<div v-for="(head, hIndex) in RoleMenuFieldHeader.$state" :key="hIndex" class="width-check">
|
||||||
|
<el-checkbox v-model="head.checked" @change="handleColumnChange($event, head.value, head.disabled)">
|
||||||
|
<span>{{ head.label }}</span>
|
||||||
|
</el-checkbox>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<div class="columns-content">
|
||||||
|
<li v-for="(c_item, c_index) in RoleMenuField.$state" :key="c_index" class="columns-item">
|
||||||
|
<div class="width-txt">{{ c_item.title }}</div>
|
||||||
|
<div v-for="(col, cIndex) in RoleMenuFieldHeader.$state" :key="cIndex" class="width-check">
|
||||||
|
<el-checkbox v-model="c_item[col.value]" class="ci-checkout" :disabled="c_item[col.disabled]"></el-checkbox>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</div>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ElMessage } from 'element-plus';
|
||||||
|
import { RoleDrawerStores } from '../stores/RoleDrawerStores';
|
||||||
|
import { RoleMenuFieldStores, RoleMenuFieldHeaderStores } from '../stores/RoleMenuFieldStores';
|
||||||
|
import { setRoleMenuField } from './api';
|
||||||
|
const RoleMenuField = RoleMenuFieldStores();
|
||||||
|
const RoleMenuFieldHeader = RoleMenuFieldHeaderStores();
|
||||||
|
const RoleDrawer = RoleDrawerStores(); // 角色-抽屉
|
||||||
|
/** 全选 */
|
||||||
|
const handleColumnChange = (val: boolean, btnType: string, disabledType: string) => {
|
||||||
|
for (const iterator of RoleMenuField.$state) {
|
||||||
|
iterator[btnType] = iterator[disabledType] ? iterator[btnType] : val;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const handleSaveField = async () => {
|
||||||
|
const res = await setRoleMenuField(RoleDrawer.$state.roleId, RoleMenuField.$state);
|
||||||
|
ElMessage({ message: res.msg, type: 'success' });
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.pccm-item {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
.menu-form-alert {
|
||||||
|
color: #fff;
|
||||||
|
line-height: 24px;
|
||||||
|
padding: 8px 16px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
border-radius: 4px;
|
||||||
|
background-color: var(--el-color-primary);
|
||||||
|
}
|
||||||
|
.menu-form-btn {
|
||||||
|
margin-left: 10px;
|
||||||
|
height: 40px;
|
||||||
|
padding: 8px 16px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
span {
|
||||||
|
margin-left: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.columns-list {
|
||||||
|
.width-txt {
|
||||||
|
width: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.width-check {
|
||||||
|
width: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.width-icon {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.columns-head {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 6px 0;
|
||||||
|
border-bottom: 1px solid #ebeef5;
|
||||||
|
box-sizing: border-box;
|
||||||
|
|
||||||
|
span {
|
||||||
|
font-weight: 900;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.columns-content {
|
||||||
|
max-height: calc(100vh - 240px); /* 视口高度 */
|
||||||
|
overflow-y: auto; /* 当内容超出高度时显示垂直滚动条 */
|
||||||
|
.columns-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 6px 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
|
||||||
|
.ci-checkout {
|
||||||
|
height: auto !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
81
web/src/views/system/role/components/RoleMenuTree.vue
Normal file
81
web/src/views/system/role/components/RoleMenuTree.vue
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
<template>
|
||||||
|
<el-tree
|
||||||
|
ref="treeRef"
|
||||||
|
:data="menuData"
|
||||||
|
:props="defaultTreeProps"
|
||||||
|
:default-checked-keys="menuDefaultCheckedKeys"
|
||||||
|
@check-change="handleMenuChange"
|
||||||
|
@node-click="handleMenuClick"
|
||||||
|
node-key="id"
|
||||||
|
check-strictly
|
||||||
|
highlight-current
|
||||||
|
show-checkbox
|
||||||
|
default-expand-all
|
||||||
|
>
|
||||||
|
</el-tree>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { onMounted, ref } from 'vue';
|
||||||
|
import { RoleDrawerStores } from '../stores/RoleDrawerStores';
|
||||||
|
import { RoleMenuTreeStores } from '../stores/RoleMenuTreeStores';
|
||||||
|
import { RoleMenuBtnStores } from '../stores/RoleMenuBtnStores';
|
||||||
|
import { RoleMenuFieldStores } from '../stores/RoleMenuFieldStores';
|
||||||
|
import { RoleMenuFieldHeaderStores } from '../stores/RoleMenuFieldStores';
|
||||||
|
import { getRoleMenu, getRoleMenuBtnField, setRoleMenu } from './api';
|
||||||
|
import { ElMessage } from 'element-plus';
|
||||||
|
import XEUtils from 'xe-utils';
|
||||||
|
import { RoleMenuTreeType } from '../types';
|
||||||
|
|
||||||
|
const RoleDrawer = RoleDrawerStores(); // 角色-抽屉
|
||||||
|
const RoleMenuTree = RoleMenuTreeStores(); // 角色-菜单
|
||||||
|
const RoleMenuBtn = RoleMenuBtnStores(); // 角色-菜单-按钮
|
||||||
|
const RoleMenuField = RoleMenuFieldStores(); // 角色-菜单-列字段
|
||||||
|
const RoleMenuFieldHeader = RoleMenuFieldHeaderStores();// 角色-菜单-列字段
|
||||||
|
const menuData = ref<RoleMenuTreeType[]>([]); // 菜单列表数据
|
||||||
|
const menuDefaultCheckedKeys = ref<(number | string | undefined)[]>([]); // 默认选中的菜单列表
|
||||||
|
// 菜单配置
|
||||||
|
const defaultTreeProps = {
|
||||||
|
children: 'children',
|
||||||
|
label: 'name',
|
||||||
|
value: 'id',
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 菜单复选框选中
|
||||||
|
* @param node:当前节点的 Node 对象
|
||||||
|
* @param checked:布尔值,表示当前节点是否被选中
|
||||||
|
*/
|
||||||
|
const handleMenuChange = (node: any, checked: boolean) => {
|
||||||
|
setRoleMenu({ roleId: RoleDrawer.roleId, menuId: node.id, isCheck: checked }).then((res: any) => {
|
||||||
|
ElMessage({ message: res.msg, type: 'success' });
|
||||||
|
});
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* 菜单点击事件
|
||||||
|
*/
|
||||||
|
const handleMenuClick = async (selectNode: RoleMenuTreeType) => {
|
||||||
|
if (!selectNode.is_catalog) {
|
||||||
|
RoleMenuTree.setRoleMenuTree(selectNode); // 更新当前选中的菜单
|
||||||
|
// 获取当前菜单的按钮列表
|
||||||
|
const { data } = await getRoleMenuBtnField({
|
||||||
|
roleId: RoleDrawer.roleId,
|
||||||
|
menuId: selectNode.id,
|
||||||
|
});
|
||||||
|
RoleMenuBtn.setState(data.menu_btn); // 更新按钮列表
|
||||||
|
RoleMenuField.setState(data.menu_field); // 更新列字段列表
|
||||||
|
} else {
|
||||||
|
RoleMenuBtn.setState([]); // 更新按钮列表
|
||||||
|
RoleMenuField.setState([]); // 更新列字段列表
|
||||||
|
}
|
||||||
|
RoleMenuFieldHeader.$reset()
|
||||||
|
};
|
||||||
|
|
||||||
|
// 页面打开后获取列表数据
|
||||||
|
onMounted(async () => {
|
||||||
|
menuData.value = await getRoleMenu({ roleId: RoleDrawer.roleId });
|
||||||
|
menuDefaultCheckedKeys.value = XEUtils.toTreeArray(menuData.value)
|
||||||
|
.filter((i) => i.isCheck)
|
||||||
|
.map((i) => i.id);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
35
web/src/views/system/role/components/RoleUsers.vue
Normal file
35
web/src/views/system/role/components/RoleUsers.vue
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
<template>
|
||||||
|
<el-transfer
|
||||||
|
v-model="RoleUsers.$state.right_users"
|
||||||
|
filterable
|
||||||
|
:titles="['未授权用户', '已授权用户']"
|
||||||
|
:data="RoleUsers.$state.all_users"
|
||||||
|
:props="{
|
||||||
|
key: 'id',
|
||||||
|
label: 'name',
|
||||||
|
}"
|
||||||
|
@change="handleChange"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { ElMessage } from 'element-plus';
|
||||||
|
import { RoleDrawerStores } from '../stores/RoleDrawerStores';
|
||||||
|
import { RoleUsersStores } from '../stores/RoleUsersStores';
|
||||||
|
import { setRoleUsers } from './api';
|
||||||
|
const RoleDrawer = RoleDrawerStores(); // 抽屉参数
|
||||||
|
const RoleUsers = RoleUsersStores(); // 角色-用户
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param value 当前右侧选中的用户
|
||||||
|
* @param direction 移动的方向
|
||||||
|
* @param movedKeys 移动的用户
|
||||||
|
*/
|
||||||
|
const handleChange = (value: number[] | string[], direction: 'left' | 'right', movedKeys: string[] | number[]) => {
|
||||||
|
setRoleUsers(RoleDrawer.$state.roleId, { direction, movedKeys }).then((res:any) => {
|
||||||
|
RoleDrawer.set_state(res.data)
|
||||||
|
ElMessage({ message: res.msg, type: 'success' });
|
||||||
|
});
|
||||||
|
};
|
||||||
|
</script>
|
||||||
121
web/src/views/system/role/components/api.ts
Normal file
121
web/src/views/system/role/components/api.ts
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
import { request } from '/@/utils/service';
|
||||||
|
import XEUtils from 'xe-utils';
|
||||||
|
/**
|
||||||
|
* 获取 角色-菜单
|
||||||
|
* @param query
|
||||||
|
*/
|
||||||
|
export function getRoleMenu(query: object) {
|
||||||
|
return request({
|
||||||
|
url: '/api/system/role_menu_button_permission/get_role_menu/',
|
||||||
|
method: 'get',
|
||||||
|
params: query,
|
||||||
|
}).then((res: any) => {
|
||||||
|
return XEUtils.toArrayTree(res.data, { key: 'id', parentKey: 'parent', children: 'children', strict: false });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 设置 角色-菜单
|
||||||
|
* @param data
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export function setRoleMenu(data: object) {
|
||||||
|
return request({
|
||||||
|
url: '/api/system/role_menu_button_permission/set_role_menu/',
|
||||||
|
method: 'put',
|
||||||
|
data,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 获取 角色-菜单-按钮-列字段
|
||||||
|
* @param query
|
||||||
|
*/
|
||||||
|
export function getRoleMenuBtnField(query: object) {
|
||||||
|
return request({
|
||||||
|
url: '/api/system/role_menu_button_permission/get_role_menu_btn_field/',
|
||||||
|
method: 'get',
|
||||||
|
params: query,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置 角色-菜单-按钮
|
||||||
|
* @param data
|
||||||
|
*/
|
||||||
|
export function setRoleMenuBtn(data: object) {
|
||||||
|
return request({
|
||||||
|
url: '/api/system/role_menu_button_permission/set_role_menu_btn/',
|
||||||
|
method: 'put',
|
||||||
|
data,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置 角色-菜单-列字段
|
||||||
|
* @param data
|
||||||
|
*/
|
||||||
|
export function setRoleMenuField(roleId: string | number | undefined, data: object) {
|
||||||
|
return request({
|
||||||
|
url: `/api/system/role_menu_button_permission/${roleId}/set_role_menu_field/`,
|
||||||
|
method: 'put',
|
||||||
|
data,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置 角色-菜单-按钮-数据权限
|
||||||
|
* @param query
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export function setRoleMenuBtnDataRange(data: object) {
|
||||||
|
return request({
|
||||||
|
url: '/api/system/role_menu_button_permission/set_role_menu_btn_data_range/',
|
||||||
|
method: 'put',
|
||||||
|
data,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前用户角色下所能授权的部门
|
||||||
|
* @param query
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export function getRoleToDeptAll(query: object) {
|
||||||
|
return request({
|
||||||
|
url: '/api/system/role_menu_button_permission/role_to_dept_all/',
|
||||||
|
method: 'get',
|
||||||
|
params: query,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取所有用户
|
||||||
|
* @param query
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export function getAllUsers() {
|
||||||
|
return request({
|
||||||
|
url: '/api/system/user/',
|
||||||
|
method: 'get',
|
||||||
|
params: { limit: 999 },
|
||||||
|
}).then((res: any) => {
|
||||||
|
return XEUtils.map(res.data, (item: any) => {
|
||||||
|
return {
|
||||||
|
id: item.id,
|
||||||
|
name: item.name,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置角色-用户
|
||||||
|
* @param query
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export function setRoleUsers(roleId: string | number | undefined, data: object) {
|
||||||
|
return request({
|
||||||
|
url: `/api/system/role/${roleId}/set_role_users/`,
|
||||||
|
method: 'put',
|
||||||
|
data,
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -1,189 +1,171 @@
|
|||||||
import {CrudOptions, AddReq, DelReq, EditReq, dict, CrudExpose, compute} from '@fast-crud/fast-crud';
|
import { CreateCrudOptionsProps, CreateCrudOptionsRet, AddReq, DelReq, EditReq, dict, compute } from '@fast-crud/fast-crud';
|
||||||
import * as api from './api';
|
import * as api from './api';
|
||||||
import {dictionary} from '/@/utils/dictionary';
|
import { dictionary } from '/@/utils/dictionary';
|
||||||
import {columnPermission} from '../../../utils/columnPermission';
|
import { successMessage } from '../../../utils/message';
|
||||||
import {successMessage} from '../../../utils/message';
|
import { auth } from '/@/utils/authFunction';
|
||||||
import {auth} from '/@/utils/authFunction'
|
|
||||||
|
|
||||||
interface CreateCrudOptionsTypes {
|
/**
|
||||||
output: any;
|
*
|
||||||
crudOptions: CrudOptions;
|
* @param crudExpose:index传递过来的示例
|
||||||
}
|
* @param context:index传递过来的自定义参数
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const createCrudOptions = function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet {
|
||||||
|
const pageRequest = async (query: any) => {
|
||||||
|
return await api.GetList(query);
|
||||||
|
};
|
||||||
|
const editRequest = async ({ form, row }: EditReq) => {
|
||||||
|
form.id = row.id;
|
||||||
|
return await api.UpdateObj(form);
|
||||||
|
};
|
||||||
|
const delRequest = async ({ row }: DelReq) => {
|
||||||
|
return await api.DelObj(row.id);
|
||||||
|
};
|
||||||
|
const addRequest = async ({ form }: AddReq) => {
|
||||||
|
return await api.AddObj(form);
|
||||||
|
};
|
||||||
|
|
||||||
//此处为crudOptions配置
|
return {
|
||||||
export const createCrudOptions = function ({
|
crudOptions: {
|
||||||
crudExpose,
|
request: {
|
||||||
rolePermission,
|
pageRequest,
|
||||||
handleDrawerOpen,
|
addRequest,
|
||||||
}: {
|
editRequest,
|
||||||
crudExpose: CrudExpose;
|
delRequest,
|
||||||
rolePermission: any;
|
},
|
||||||
handleDrawerOpen: Function;
|
pagination: {
|
||||||
}): CreateCrudOptionsTypes {
|
show: true,
|
||||||
const pageRequest = async (query: any) => {
|
},
|
||||||
return await api.GetList(query);
|
actionbar: {
|
||||||
};
|
buttons: {
|
||||||
const editRequest = async ({form, row}: EditReq) => {
|
add: {
|
||||||
form.id = row.id;
|
show: auth('role:Create'),
|
||||||
return await api.UpdateObj(form);
|
},
|
||||||
};
|
},
|
||||||
const delRequest = async ({row}: DelReq) => {
|
},
|
||||||
return await api.DelObj(row.id);
|
rowHandle: {
|
||||||
};
|
//固定右侧
|
||||||
const addRequest = async ({form}: AddReq) => {
|
fixed: 'right',
|
||||||
return await api.AddObj(form);
|
width: 320,
|
||||||
};
|
buttons: {
|
||||||
|
view: {
|
||||||
//权限判定
|
show: true,
|
||||||
|
},
|
||||||
// @ts-ignore
|
edit: {
|
||||||
// @ts-ignore
|
show: auth('role:Update'),
|
||||||
return {
|
},
|
||||||
crudOptions: {
|
remove: {
|
||||||
request: {
|
show: auth('role:Delete'),
|
||||||
pageRequest,
|
},
|
||||||
addRequest,
|
permission: {
|
||||||
editRequest,
|
type: 'primary',
|
||||||
delRequest,
|
text: '权限配置',
|
||||||
},
|
show: auth('role:Permission'),
|
||||||
pagination: {
|
click: (clickContext: any): void => {
|
||||||
show: true
|
const { row } = clickContext;
|
||||||
},
|
context.RoleDrawer.handleDrawerOpen(row);
|
||||||
actionbar: {
|
context.RoleMenuBtn.setState([]);
|
||||||
buttons: {
|
context.RoleMenuField.setState([]);
|
||||||
add: {
|
},
|
||||||
show: auth('role:Create')
|
},
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
},
|
form: {
|
||||||
rowHandle: {
|
col: { span: 24 },
|
||||||
//固定右侧
|
labelWidth: '100px',
|
||||||
fixed: 'right',
|
wrapper: {
|
||||||
width: 320,
|
is: 'el-dialog',
|
||||||
buttons: {
|
width: '600px',
|
||||||
view: {
|
},
|
||||||
show: true,
|
},
|
||||||
},
|
columns: {
|
||||||
edit: {
|
_index: {
|
||||||
show: auth('role:Update'),
|
title: '序号',
|
||||||
},
|
form: { show: false },
|
||||||
remove: {
|
column: {
|
||||||
show: auth('role:Delete'),
|
type: 'index',
|
||||||
},
|
align: 'center',
|
||||||
permission: {
|
width: '70px',
|
||||||
type: 'primary',
|
columnSetDisabled: true, //禁止在列设置中选择
|
||||||
text: '权限配置',
|
},
|
||||||
show: auth('role:Permission'),
|
},
|
||||||
tooltip: {
|
id: {
|
||||||
placement: 'top',
|
title: 'ID',
|
||||||
content: '权限配置',
|
column: { show: false },
|
||||||
},
|
search: { show: false },
|
||||||
click: (context: any): void => {
|
form: { show: false },
|
||||||
const {row} = context;
|
},
|
||||||
handleDrawerOpen(row);
|
name: {
|
||||||
},
|
title: '角色名称',
|
||||||
},
|
search: { show: true },
|
||||||
},
|
column: {
|
||||||
},
|
minWidth: 120,
|
||||||
form: {
|
sortable: 'custom',
|
||||||
col: {span: 24},
|
},
|
||||||
labelWidth: '100px',
|
form: {
|
||||||
wrapper: {
|
rules: [{ required: true, message: '角色名称必填' }],
|
||||||
is: 'el-dialog',
|
component: {
|
||||||
width: '600px',
|
placeholder: '请输入角色名称',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
columns: {
|
},
|
||||||
_index: {
|
key: {
|
||||||
title: '序号',
|
title: '权限标识',
|
||||||
form: {show: false},
|
search: { show: false },
|
||||||
column: {
|
column: {
|
||||||
type: 'index',
|
minWidth: 120,
|
||||||
align: 'center',
|
sortable: 'custom',
|
||||||
width: '70px',
|
columnSetDisabled: true,
|
||||||
columnSetDisabled: true, //禁止在列设置中选择
|
},
|
||||||
},
|
form: {
|
||||||
},
|
rules: [{ required: true, message: '权限标识必填' }],
|
||||||
id: {
|
component: {
|
||||||
title: 'ID',
|
placeholder: '输入权限标识',
|
||||||
type: 'text',
|
},
|
||||||
column: {show: false},
|
},
|
||||||
search: {show: false},
|
valueBuilder(context) {
|
||||||
form: {show: false},
|
const { row, key } = context;
|
||||||
},
|
return row[key];
|
||||||
name: {
|
},
|
||||||
title: '角色名称',
|
},
|
||||||
type: 'text',
|
sort: {
|
||||||
search: {show: true},
|
title: '排序',
|
||||||
column: {
|
search: { show: false },
|
||||||
minWidth: 120,
|
type: 'number',
|
||||||
sortable: 'custom',
|
column: {
|
||||||
},
|
minWidth: 90,
|
||||||
form: {
|
sortable: 'custom',
|
||||||
rules: [{required: true, message: '角色名称必填'}],
|
},
|
||||||
component: {
|
form: {
|
||||||
placeholder: '请输入角色名称',
|
rules: [{ required: true, message: '排序必填' }],
|
||||||
},
|
value: 1,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
key: {
|
status: {
|
||||||
title: '权限标识',
|
title: '状态',
|
||||||
type: 'text',
|
search: { show: true },
|
||||||
search: {show: false},
|
type: 'dict-radio',
|
||||||
column: {
|
column: {
|
||||||
minWidth: 120,
|
width: 100,
|
||||||
sortable: 'custom',
|
component: {
|
||||||
columnSetDisabled: true,
|
name: 'fs-dict-switch',
|
||||||
},
|
activeText: '',
|
||||||
form: {
|
inactiveText: '',
|
||||||
rules: [{required: true, message: '权限标识必填'}],
|
style: '--el-switch-on-color: var(--el-color-primary); --el-switch-off-color: #dcdfe6',
|
||||||
component: {
|
onChange: compute((context) => {
|
||||||
placeholder: '输入权限标识',
|
return () => {
|
||||||
},
|
api.UpdateObj(context.row).then((res: APIResponseData) => {
|
||||||
},
|
successMessage(res.msg as string);
|
||||||
valueBuilder(context) {
|
});
|
||||||
const {row, key} = context
|
};
|
||||||
return row[key]
|
}),
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
sort: {
|
dict: dict({
|
||||||
title: '排序',
|
value: dictionary('button_status_bool'),
|
||||||
search: {show: false},
|
}),
|
||||||
type: 'number',
|
},
|
||||||
column: {
|
},
|
||||||
minWidth: 90,
|
},
|
||||||
sortable: 'custom',
|
};
|
||||||
},
|
|
||||||
form: {
|
|
||||||
rules: [{required: true, message: '排序必填'}],
|
|
||||||
value: 1,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
status: {
|
|
||||||
title: '状态',
|
|
||||||
search: {show: true},
|
|
||||||
type: 'dict-radio',
|
|
||||||
column: {
|
|
||||||
width: 100,
|
|
||||||
component: {
|
|
||||||
name: 'fs-dict-switch',
|
|
||||||
activeText: '',
|
|
||||||
inactiveText: '',
|
|
||||||
style: '--el-switch-on-color: var(--el-color-primary); --el-switch-off-color: #dcdfe6',
|
|
||||||
onChange: compute((context) => {
|
|
||||||
return () => {
|
|
||||||
api.UpdateObj(context.row).then((res: APIResponseData) => {
|
|
||||||
successMessage(res.msg as string);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
dict: dict({
|
|
||||||
data: dictionary('button_status_bool'),
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,69 +1,36 @@
|
|||||||
<template>
|
<template>
|
||||||
<fs-page>
|
<fs-page>
|
||||||
<fs-crud ref="crudRef" v-bind="crudBinding">
|
<fs-crud ref="crudRef" v-bind="crudBinding"> </fs-crud>
|
||||||
<template #cell_url="scope">
|
<PermissionDrawerCom />
|
||||||
<el-tag size="small">{{ scope.row.url }}</el-tag>
|
|
||||||
</template>
|
|
||||||
</fs-crud>
|
|
||||||
|
|
||||||
<permission ref="rolePermission"></permission>
|
|
||||||
|
|
||||||
<PermissionComNew v-model:drawerVisible="drawerVisible" :roleId="roleId" :roleName="roleName" @drawerClose="handleDrawerClose" />
|
|
||||||
</fs-page>
|
</fs-page>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup name="role">
|
<script lang="ts" setup name="role">
|
||||||
import {ref, onMounted, inject, onBeforeUpdate} from 'vue';
|
import { defineAsyncComponent, onMounted } from 'vue';
|
||||||
|
import { useFs } from '@fast-crud/fast-crud';
|
||||||
import { GetPermission } from './api';
|
|
||||||
import { useExpose, useCrud } from '@fast-crud/fast-crud';
|
|
||||||
import { createCrudOptions } from './crud';
|
import { createCrudOptions } from './crud';
|
||||||
import PermissionComNew from './components/PermissionComNew/index.vue';
|
import { RoleDrawerStores } from './stores/RoleDrawerStores';
|
||||||
import _ from "lodash-es";
|
import { RoleMenuBtnStores } from './stores/RoleMenuBtnStores';
|
||||||
import {handleColumnPermission} from "/@/utils/columnPermission";
|
import { RoleMenuFieldStores } from './stores/RoleMenuFieldStores';
|
||||||
let drawerVisible = ref(false);
|
import { RoleUsersStores } from './stores/RoleUsersStores';
|
||||||
let roleId = ref(null);
|
|
||||||
let roleName = ref(null);
|
|
||||||
|
|
||||||
const rolePermission = ref();
|
const PermissionDrawerCom = defineAsyncComponent(() => import('./components/RoleDrawer.vue'));
|
||||||
// crud组件的ref
|
|
||||||
const crudRef = ref();
|
|
||||||
// crud 配置的ref
|
|
||||||
const crudBinding = ref();
|
|
||||||
|
|
||||||
|
const RoleDrawer = RoleDrawerStores(); // 角色-抽屉
|
||||||
const handleDrawerOpen = (row: any) => {
|
const RoleMenuBtn = RoleMenuBtnStores(); // 角色-菜单
|
||||||
roleId.value = row.id;
|
const RoleMenuField = RoleMenuFieldStores();// 角色-菜单-字段
|
||||||
roleName.value = row.name;
|
const RoleUsers = RoleUsersStores();// 角色-用户
|
||||||
drawerVisible.value = true;
|
const { crudBinding, crudRef, crudExpose } = useFs({
|
||||||
};
|
createCrudOptions,
|
||||||
|
context: { RoleDrawer, RoleMenuBtn, RoleMenuField },
|
||||||
const handleDrawerClose = () => {
|
|
||||||
drawerVisible.value = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
const { crudExpose } = useExpose({ crudRef, crudBinding });
|
|
||||||
|
|
||||||
// 你的crud配置
|
|
||||||
const { crudOptions } = createCrudOptions({ crudExpose, rolePermission, handleDrawerOpen });
|
|
||||||
|
|
||||||
// 初始化crud配置
|
|
||||||
const { resetCrudOptions } = useCrud({
|
|
||||||
crudExpose,
|
|
||||||
crudOptions,
|
|
||||||
context: {},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// 页面打开后获取列表数据
|
// 页面打开后获取列表数据
|
||||||
onMounted( async () => {
|
onMounted(async () => {
|
||||||
|
// 刷新
|
||||||
const newOptions = await handleColumnPermission(GetPermission,crudOptions)
|
|
||||||
|
|
||||||
|
|
||||||
//重置crudBinding
|
|
||||||
//resetCrudOptions(newOptions);
|
|
||||||
crudExpose.doRefresh();
|
crudExpose.doRefresh();
|
||||||
});
|
// 获取全部用户
|
||||||
|
RoleUsers.get_all_users();
|
||||||
|
|
||||||
defineExpose(rolePermission);
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
37
web/src/views/system/role/stores/RoleDrawerStores.ts
Normal file
37
web/src/views/system/role/stores/RoleDrawerStores.ts
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
import { defineStore } from 'pinia';
|
||||||
|
import { RoleDrawerType } from '../types';
|
||||||
|
/**
|
||||||
|
* 权限配置:抽屉
|
||||||
|
*/
|
||||||
|
const initialState: RoleDrawerType = {
|
||||||
|
drawerVisible: false,
|
||||||
|
roleId: undefined,
|
||||||
|
roleName: undefined,
|
||||||
|
users: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
export const RoleDrawerStores = defineStore('RoleDrawerStores', {
|
||||||
|
state: (): RoleDrawerType => ({
|
||||||
|
...initialState,
|
||||||
|
}),
|
||||||
|
actions: {
|
||||||
|
/**
|
||||||
|
* 打开权限修改抽屉
|
||||||
|
*/
|
||||||
|
handleDrawerOpen(row: any) {
|
||||||
|
this.drawerVisible = true;
|
||||||
|
this.set_state(row);
|
||||||
|
},
|
||||||
|
set_state(row: any) {
|
||||||
|
this.roleName = row.name;
|
||||||
|
this.roleId = row.id;
|
||||||
|
this.users = row.users;
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 关闭权限修改抽屉
|
||||||
|
*/
|
||||||
|
handleDrawerClose() {
|
||||||
|
Object.assign(this.$state, initialState);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
24
web/src/views/system/role/stores/RoleMenuBtnStores.ts
Normal file
24
web/src/views/system/role/stores/RoleMenuBtnStores.ts
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
import { defineStore } from 'pinia';
|
||||||
|
import { RoleMenuBtnType } from '../types';
|
||||||
|
/**
|
||||||
|
* 权限配置:角色-菜单-按钮
|
||||||
|
*/
|
||||||
|
|
||||||
|
export const RoleMenuBtnStores = defineStore('RoleMenuBtnStores', {
|
||||||
|
state: (): RoleMenuBtnType[] => [],
|
||||||
|
actions: {
|
||||||
|
/**
|
||||||
|
* 初始化
|
||||||
|
*/
|
||||||
|
setState(data: RoleMenuBtnType[]) {
|
||||||
|
this.$state = data;
|
||||||
|
this.$state.length = data.length;
|
||||||
|
},
|
||||||
|
updateState(data: RoleMenuBtnType) {
|
||||||
|
const index = this.$state.findIndex((item) => item.id === data.id);
|
||||||
|
if (index !== -1) {
|
||||||
|
this.$state[index] = data;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
24
web/src/views/system/role/stores/RoleMenuFieldStores.ts
Normal file
24
web/src/views/system/role/stores/RoleMenuFieldStores.ts
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
import { defineStore } from 'pinia';
|
||||||
|
import { RoleMenuFieldType, RoleMenuFieldHeaderType } from '../types';
|
||||||
|
/**
|
||||||
|
* 权限配置:角色-菜单-列字段
|
||||||
|
*/
|
||||||
|
|
||||||
|
export const RoleMenuFieldStores = defineStore('RoleMenuFieldStores', {
|
||||||
|
state: (): RoleMenuFieldType[] => [],
|
||||||
|
actions: {
|
||||||
|
/** 重置 */
|
||||||
|
setState(data: RoleMenuFieldType[]) {
|
||||||
|
this.$state = data;
|
||||||
|
this.$state.length = data.length;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export const RoleMenuFieldHeaderStores = defineStore('RoleMenuFieldHeaderStores', {
|
||||||
|
state: (): RoleMenuFieldHeaderType[] => [
|
||||||
|
{ value: 'is_create', label: '新增可见', disabled: 'disabled_create', checked: false },
|
||||||
|
{ value: 'is_update', label: '编辑可见', disabled: 'disabled_update', checked: false },
|
||||||
|
{ value: 'is_query', label: '列表可见', disabled: 'disabled_query', checked: false },
|
||||||
|
],
|
||||||
|
});
|
||||||
21
web/src/views/system/role/stores/RoleMenuTreeStores.ts
Normal file
21
web/src/views/system/role/stores/RoleMenuTreeStores.ts
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import { defineStore } from 'pinia';
|
||||||
|
import { RoleMenuTreeType } from '../types';
|
||||||
|
/**
|
||||||
|
* 权限抽屉:角色-菜单
|
||||||
|
*/
|
||||||
|
|
||||||
|
export const RoleMenuTreeStores = defineStore('RoleMenuTreeStores', {
|
||||||
|
state: (): RoleMenuTreeType => ({
|
||||||
|
id: 0,
|
||||||
|
parent: 0,
|
||||||
|
name: '',
|
||||||
|
isCheck: false,
|
||||||
|
is_catalog: false,
|
||||||
|
}),
|
||||||
|
actions: {
|
||||||
|
/** 赋值 */
|
||||||
|
setRoleMenuTree(data: RoleMenuTreeType) {
|
||||||
|
this.$state = data;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
24
web/src/views/system/role/stores/RoleUsersStores.ts
Normal file
24
web/src/views/system/role/stores/RoleUsersStores.ts
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
import { defineStore } from 'pinia';
|
||||||
|
import { RoleUsersType } from '../types';
|
||||||
|
import { getAllUsers } from '../components/api';
|
||||||
|
import XEUtils from 'xe-utils';
|
||||||
|
/**
|
||||||
|
* 权限抽屉:角色-用户
|
||||||
|
*/
|
||||||
|
|
||||||
|
export const RoleUsersStores = defineStore('RoleUsersStores', {
|
||||||
|
state: (): RoleUsersType => ({
|
||||||
|
all_users: [],
|
||||||
|
right_users: [],
|
||||||
|
}),
|
||||||
|
actions: {
|
||||||
|
get_all_users() {
|
||||||
|
getAllUsers().then((res: any) => {
|
||||||
|
this.$state.all_users = res;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
set_right_users(users: any) {
|
||||||
|
this.$state.right_users = XEUtils.map(users, (item: any) => item.id);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -1,27 +1,99 @@
|
|||||||
import { CrudOptions, CrudExpose } from '@fast-crud/fast-crud';
|
/**角色列表数据类型 */
|
||||||
|
|
||||||
export interface CreateCrudReturnTypes {
|
|
||||||
crudOptions: CrudOptions;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface CreateCrudOptionsTypes {
|
|
||||||
crudExpose: CrudExpose;
|
|
||||||
configPermission: Function;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface RoleItemType {
|
export interface RoleItemType {
|
||||||
id: string | number;
|
id: string | number;
|
||||||
modifier_name: string;
|
modifier_name: string;
|
||||||
creator_name: string;
|
creator_name: string;
|
||||||
create_datetime: string;
|
create_datetime: string;
|
||||||
update_datetime: string;
|
update_datetime: string;
|
||||||
description: string;
|
description: string;
|
||||||
modifier: string;
|
modifier: string;
|
||||||
dept_belong_id: string;
|
dept_belong_id: string;
|
||||||
name: string;
|
name: string;
|
||||||
key: string;
|
key: string;
|
||||||
sort: number;
|
sort: number;
|
||||||
status: boolean;
|
status: boolean;
|
||||||
admin: boolean;
|
admin: boolean;
|
||||||
creator: string;
|
creator: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface UsersType {
|
||||||
|
id: string | number;
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
export interface RoleUsersType {
|
||||||
|
all_users: UsersType[];
|
||||||
|
right_users: UsersType[];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 权限配置 抽屉组件参数数据类型
|
||||||
|
*/
|
||||||
|
export interface RoleDrawerType {
|
||||||
|
/** 是否显示抽屉*/
|
||||||
|
drawerVisible: boolean;
|
||||||
|
/** 角色id*/
|
||||||
|
roleId: string | number | undefined;
|
||||||
|
/** 角色名称*/
|
||||||
|
roleName: string | undefined;
|
||||||
|
/** 用户*/
|
||||||
|
users: UsersType[];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 菜单数据类型
|
||||||
|
*/
|
||||||
|
export interface RoleMenuTreeType {
|
||||||
|
id: number | string | undefined;
|
||||||
|
/** 父级id */
|
||||||
|
parent: number | string | undefined;
|
||||||
|
name: string;
|
||||||
|
/** 是否选中 */
|
||||||
|
isCheck: boolean;
|
||||||
|
/** 是否是目录 */
|
||||||
|
is_catalog: boolean;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 菜单-按钮数据类型
|
||||||
|
*/
|
||||||
|
export interface RoleMenuBtnType {
|
||||||
|
id: string | number;
|
||||||
|
menu_btn_pre_id: string | number;
|
||||||
|
/** 是否选中 */
|
||||||
|
isCheck: boolean;
|
||||||
|
/** 按钮名称 */
|
||||||
|
name: string;
|
||||||
|
/** 数据权限范围 */
|
||||||
|
data_range: number | null;
|
||||||
|
/** 自定义部门 */
|
||||||
|
dept: number[];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 菜单-列字段数据类型
|
||||||
|
*/
|
||||||
|
export interface RoleMenuFieldType {
|
||||||
|
id: string | number | boolean;
|
||||||
|
/** 模型表字段名 */
|
||||||
|
field_name: string;
|
||||||
|
/** 字段显示名 */
|
||||||
|
title: string;
|
||||||
|
/** 是否可查询 */
|
||||||
|
is_query: boolean;
|
||||||
|
/** 是否可创建 */
|
||||||
|
is_create: boolean;
|
||||||
|
/** 是否可更新 */
|
||||||
|
is_update: boolean;
|
||||||
|
[key: string]: string | number | boolean;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 菜单-列字段-标题数据类型
|
||||||
|
*/
|
||||||
|
export interface RoleMenuFieldHeaderType {
|
||||||
|
value: string;
|
||||||
|
/** 模型表字段名 */
|
||||||
|
label: string;
|
||||||
|
/** 字段显示名 */
|
||||||
|
disabled: string;
|
||||||
|
/** 是否可查询 */
|
||||||
|
checked: boolean;
|
||||||
|
}
|
||||||
|
|||||||
@@ -259,10 +259,10 @@ export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProp
|
|||||||
}),
|
}),
|
||||||
column: {
|
column: {
|
||||||
minWidth: 200, //最小列宽
|
minWidth: 200, //最小列宽
|
||||||
formatter({ value, row, index }) {
|
// formatter({ value, row, index }) {
|
||||||
const values = row.role_info.map((item: any) => item.name);
|
// const values = row.role_info.map((item: any) => item.name);
|
||||||
return values.join(',')
|
// return values.join(',')
|
||||||
}
|
// }
|
||||||
},
|
},
|
||||||
form: {
|
form: {
|
||||||
rules: [
|
rules: [
|
||||||
@@ -384,12 +384,13 @@ export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProp
|
|||||||
},
|
},
|
||||||
avatar: {
|
avatar: {
|
||||||
title: '头像',
|
title: '头像',
|
||||||
type: 'avatar-cropper',
|
type: 'avatar-uploader',
|
||||||
|
align: 'center',
|
||||||
form: {
|
form: {
|
||||||
show: false,
|
show: false,
|
||||||
},
|
},
|
||||||
column: {
|
column: {
|
||||||
minWidth: 400, //最小列宽
|
minWidth: 100, //最小列宽
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
...commonCrudConfig({
|
...commonCrudConfig({
|
||||||
|
|||||||
@@ -33,6 +33,15 @@
|
|||||||
<template #actionbar-right>
|
<template #actionbar-right>
|
||||||
<importExcel api="api/system/user/" v-auth="'user:Import'">导入</importExcel>
|
<importExcel api="api/system/user/" v-auth="'user:Import'">导入</importExcel>
|
||||||
</template>
|
</template>
|
||||||
|
<template #cell_avatar="scope">
|
||||||
|
<div v-if="scope.row.avatar" style="display: flex; justify-content: center; align-items: center;">
|
||||||
|
<el-image
|
||||||
|
style="width: 50px; height: 50px; border-radius: 50%; aspect-ratio: 1 /1 ; "
|
||||||
|
:src="getBaseURL(scope.row.avatar)"
|
||||||
|
:preview-src-list="[getBaseURL(scope.row.avatar)]"
|
||||||
|
:preview-teleported="true" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
</fs-crud>
|
</fs-crud>
|
||||||
</el-card>
|
</el-card>
|
||||||
</el-col>
|
</el-col>
|
||||||
@@ -50,6 +59,8 @@ import {ref, onMounted, watch, toRaw, h} from 'vue';
|
|||||||
import XEUtils from 'xe-utils';
|
import XEUtils from 'xe-utils';
|
||||||
import {getElementLabelLine} from 'element-tree-line';
|
import {getElementLabelLine} from 'element-tree-line';
|
||||||
import importExcel from '/@/components/importExcel/index.vue'
|
import importExcel from '/@/components/importExcel/index.vue'
|
||||||
|
import {getBaseURL} from '/@/utils/baseUrl';
|
||||||
|
|
||||||
|
|
||||||
const ElementTreeLine = getElementLabelLine(h);
|
const ElementTreeLine = getElementLabelLine(h);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user