角色管理完成

pull/1/head
李强 2021-02-27 01:53:08 +08:00
parent 7a68aee719
commit 68c3e3fa92
10 changed files with 178 additions and 65 deletions

View File

@ -4,19 +4,19 @@ from apps.op_drf.models import CoreModel
class Role(CoreModel):
PURVIEW_CHOICES = (
(0, "全部数据权限"),
(1, "自定数据权限"),
(2, "本部门数据权限"),
(3, "本部门及以下数据权限"),
(4, "仅本人数据权限"),
DATASCOPE_CHOICES = (
('1', "全部数据权限"),
('2', "自定数据权限"),
('3', "本部门数据权限"),
('4', "本部门及以下数据权限"),
('5', "仅本人数据权限"),
)
name = CharField(max_length=64, verbose_name="角色名称")
roleName = CharField(max_length=64, verbose_name="角色名称")
roleKey = CharField(max_length=64, verbose_name="权限字符")
orderNum = IntegerField(verbose_name="角色顺序")
status = BooleanField(default=False, verbose_name="角色状态")
roleSort = IntegerField(verbose_name="角色顺序")
status = CharField(max_length=8, verbose_name="角色状态")
admin = BooleanField(default=False, verbose_name="是否为admin")
purview = IntegerField(default=0, choices=PURVIEW_CHOICES, verbose_name="权限范围")
dataScope = CharField(max_length=8, choices=DATASCOPE_CHOICES, verbose_name="权限范围")
remark = TextField(verbose_name="备注", help_text="备注", null=True)
dept = ManyToManyField(to='Dept', verbose_name='数据权限-关联部门')
menu = ManyToManyField(to='Menu', verbose_name='关联菜单权限')
@ -26,4 +26,4 @@ class Role(CoreModel):
verbose_name_plural = verbose_name
def __str__(self):
return f"{self.name}"
return f"{self.roleName}"

View File

@ -8,6 +8,7 @@ from apps.permission.models import Menu, Dept, Post, Role, UserProfile
# ************** 用户管理 序列化器 ************** #
# ================================================= #
class UserProfileSerializer(CustomModelSerializer):
"""
简单用户序列化器
@ -63,6 +64,18 @@ class MenuCreateUpdateSerializer(CustomModelSerializer):
read_only_fields = ('update_datetime', 'create_datetime', 'creator', 'modifier')
class MenuTreeSerializer(serializers.ModelSerializer):
"""
菜单树形架构序列化器:递归序列化所有深度的子菜单
"""
label = serializers.CharField(source='name', default='')
parentId = serializers.IntegerField(source="parentId.id", default=0)
class Meta:
model = Menu
fields = ('id', 'label', 'parentId')
# ================================================= #
# ************** 部门管理 序列化器 ************** #
# ================================================= #
@ -72,6 +85,7 @@ class DeptSerializer(CustomModelSerializer):
部门管理 简单序列化器
"""
parentId = serializers.IntegerField(source="parentId.id", default=0)
class Meta:
model = Dept
exclude = ('description', 'creator', 'modifier')
@ -91,6 +105,18 @@ class DeptCreateUpdateSerializer(CustomModelSerializer):
read_only_fields = ('update_datetime', 'create_datetime', 'creator', 'modifier')
class DeptTreeSerializer(serializers.ModelSerializer):
"""
部门树形架构序列化器:递归序列化所有深度的子部门
"""
label = serializers.CharField(source='deptName', default='')
parentId = serializers.IntegerField(source="parentId.id", default=0)
class Meta:
model = Dept
fields = ('id', 'label', 'parentId')
# ================================================= #
# ************** 岗位管理 序列化器 ************** #
# ================================================= #
@ -137,10 +163,18 @@ class RoleCreateUpdateSerializer(CustomModelSerializer):
"""
角色管理 创建/更新时的列化器
"""
menu = MenuSerializer(many=True, read_only=True)
dept = DeptSerializer(many=True, read_only=True)
def validate(self, attrs: dict):
return super().validate(attrs)
def save(self, **kwargs):
data = super().save(**kwargs)
data.dept.set(self.initial_data.get('dept'))
data.menu.set(self.initial_data.get('menu'))
return data
class Meta:
model = Role
exclude = ('description', 'creator', 'modifier')

View File

@ -11,7 +11,13 @@ router.register(r'post', PostModelViewSet)
router.register(r'role', RoleModelViewSet)
urlpatterns = [
re_path('dept/exclude/(?P<pk>.*)/', DeptModelViewSet.as_view({'get': 'exclude_list'}), name='api_token_auth'),
re_path('dept/exclude/(?P<pk>.*)/', DeptModelViewSet.as_view({'get': 'exclude_list'})),
re_path('dept/treeselect/', DeptModelViewSet.as_view({'get': 'tree_select_list'})),
re_path('menus/treeselect/', MenuModelViewSet.as_view({'get': 'tree_select_list'})),
# 根据角色ID查询菜单下拉树结构
re_path('menus/roleMenuTreeselect/(?P<pk>.*)/', MenuModelViewSet.as_view({'get': 'role_menu_tree_select'})),
# 根据角色ID查询部门树结构
re_path('dept/roleDeptTreeselect/(?P<pk>.*)/', DeptModelViewSet.as_view({'get': 'role_dept_tree_select'})),
]
urlpatterns += router.urls

View File

@ -9,7 +9,7 @@ from apps.permission.filters import MenuFilter, DeptFilter, PostFilter, RoleFilt
from apps.permission.models import Role, Menu, Dept, Post
from apps.permission.serializers import UserProfileSerializer, MenuSerializer, RoleSerializer, \
MenuCreateUpdateSerializer, DeptSerializer, DeptCreateUpdateSerializer, PostSerializer, PostCreateUpdateSerializer, \
RoleCreateUpdateSerializer
RoleCreateUpdateSerializer, DeptTreeSerializer, MenuTreeSerializer
from utils.response import SuccessResponse
@ -57,6 +57,38 @@ class MenuModelViewSet(CustomModelViewSet):
search_fields = ('name',)
ordering = 'create_datetime' # 默认排序
def tree_select_list(self, request: Request, *args, **kwargs):
"""
递归获取部门树
:param request:
:param args:
:param kwargs:
:return:
"""
queryset = self.filter_queryset(self.get_queryset())
if hasattr(self, 'handle_logging'):
self.handle_logging(request, *args, **kwargs)
serializer = MenuTreeSerializer(queryset, many=True)
return SuccessResponse(serializer.data)
def role_menu_tree_select(self, request: Request, *args, **kwargs):
"""
根据角色ID查询菜单下拉树结构
:param request:
:param args:
:param kwargs:
:return:
"""
menu_queryset = Menu.objects.filter(role__id=kwargs.get('pk')).values_list('id', flat=True)
queryset = self.filter_queryset(self.get_queryset())
if hasattr(self, 'handle_logging'):
self.handle_logging(request, *args, **kwargs)
serializer = MenuTreeSerializer(queryset, many=True)
return SuccessResponse({
'menus': serializer.data,
'checkedKeys': menu_queryset
})
class DeptModelViewSet(CustomModelViewSet):
"""
@ -74,6 +106,13 @@ class DeptModelViewSet(CustomModelViewSet):
ordering = 'create_datetime' # 默认排序
def exclude_list(self, request: Request, *args, **kwargs):
"""
过滤剔除同级部门
:param request:
:param args:
:param kwargs:
:return:
"""
dept_queryset = Dept.objects.filter(id=kwargs.get('pk')).first()
parentId = dept_queryset.parentId if dept_queryset else ''
queryset = self.queryset.exclude(parentId=parentId).order_by('orderNum')
@ -82,6 +121,38 @@ class DeptModelViewSet(CustomModelViewSet):
serializer = self.get_serializer(queryset, many=True)
return SuccessResponse(serializer.data)
def tree_select_list(self, request: Request, *args, **kwargs):
"""
递归获取部门树
:param request:
:param args:
:param kwargs:
:return:
"""
queryset = self.filter_queryset(self.get_queryset())
if hasattr(self, 'handle_logging'):
self.handle_logging(request, *args, **kwargs)
serializer = DeptTreeSerializer(queryset, many=True)
return SuccessResponse(serializer.data)
def role_dept_tree_select(self, request: Request, *args, **kwargs):
"""
根据角色ID查询部门树结构
:param request:
:param args:
:param kwargs:
:return:
"""
dept_queryset = Dept.objects.filter(role__id=kwargs.get('pk')).values_list('id', flat=True)
queryset = self.filter_queryset(self.get_queryset())
if hasattr(self, 'handle_logging'):
self.handle_logging(request, *args, **kwargs)
serializer = DeptTreeSerializer(queryset, many=True)
return SuccessResponse({
'depts': serializer.data,
'checkedKeys': dept_queryset
})
class PostModelViewSet(CustomModelViewSet):
"""
@ -96,7 +167,7 @@ class PostModelViewSet(CustomModelViewSet):
# destroy_extra_permission_classes = (IsManagerPermission,)
# create_extra_permission_classes = (IsManagerPermission,)
search_fields = ('name',)
ordering = ['postSort','create_datetime'] # 默认排序
ordering = ['postSort', 'create_datetime'] # 默认排序
class RoleModelViewSet(CustomModelViewSet):

View File

@ -28,7 +28,7 @@ export function getDept(deptId) {
// 查询部门下拉树结构
export function treeselect() {
return request({
url: '/permission/dept/treeselect',
url: '/permission/dept/treeselect/',
method: 'get'
})
}
@ -36,7 +36,7 @@ export function treeselect() {
// 根据角色ID查询部门树结构
export function roleDeptTreeselect(roleId) {
return request({
url: '/permission/dept/roleDeptTreeselect/' + roleId,
url: '/permission/dept/roleDeptTreeselect/' + roleId + '/',
method: 'get'
})
}

View File

@ -20,7 +20,7 @@ export function getMenu(menuId) {
// 查询菜单下拉树结构
export function treeselect() {
return request({
url: '/system/menu/treeselect',
url: '/permission/menus/treeselect/',
method: 'get'
})
}
@ -28,7 +28,7 @@ export function treeselect() {
// 根据角色ID查询菜单下拉树结构
export function roleMenuTreeselect(roleId) {
return request({
url: '/system/menu/roleMenuTreeselect/' + roleId,
url: '/permission/menus/roleMenuTreeselect/' + roleId + '/',
method: 'get'
})
}

View File

@ -3,7 +3,7 @@ import request from '@/utils/request'
// 查询角色列表
export function listRole(query) {
return request({
url: '/system/role/list',
url: '/permission/role/',
method: 'get',
params: query
})
@ -12,7 +12,7 @@ export function listRole(query) {
// 查询角色详细
export function getRole(roleId) {
return request({
url: '/system/role/' + roleId,
url: '/permission/role/' + roleId + '/',
method: 'get'
})
}
@ -20,7 +20,7 @@ export function getRole(roleId) {
// 新增角色
export function addRole(data) {
return request({
url: '/system/role',
url: '/permission/role/',
method: 'post',
data: data
})
@ -29,7 +29,7 @@ export function addRole(data) {
// 修改角色
export function updateRole(data) {
return request({
url: '/system/role',
url: '/permission/role/' + data.id + '/',
method: 'put',
data: data
})
@ -38,7 +38,7 @@ export function updateRole(data) {
// 角色数据权限
export function dataScope(data) {
return request({
url: '/system/role/dataScope',
url: '/permission/role/' + data.id + '/',
method: 'put',
data: data
})
@ -51,7 +51,7 @@ export function changeRoleStatus(roleId, status) {
status
}
return request({
url: '/system/role/changeStatus',
url: '/permission/role/changeStatus/',
method: 'put',
data: data
})
@ -60,7 +60,7 @@ export function changeRoleStatus(roleId, status) {
// 删除角色
export function delRole(roleId) {
return request({
url: '/system/role/' + roleId,
url: '/permission/role/' + roleId + '/',
method: 'delete'
})
}
@ -68,7 +68,7 @@ export function delRole(roleId) {
// 导出角色
export function exportRole(query) {
return request({
url: '/system/role/export',
url: '/permission/role/export/',
method: 'get',
params: query
})

View File

@ -140,6 +140,7 @@ export function handleTree(data, id, parentId, children, rootId) {
//数字比较函数
return a.orderNum - b.orderNum;
}
console.log(1,data)
rootId = rootId || Math.min.apply(Math, data.map(item => { return item[parentId] })) || 0
//对源数据深度克隆
const cloneData = JSON.parse(JSON.stringify(data))

View File

@ -271,9 +271,9 @@
//
open: false,
//
visibleOptions: [{dictLabel: '显示', dictValue: '1',}, {dictLabel: '隐藏', dictValue: '0',}],
visibleOptions: [],
//
statusOptions: [{dictLabel: '正常', dictValue: '1',}, {dictLabel: '停用', dictValue: '0',}],
statusOptions: [],
//
menuTypeOptions: [{dictLabel: '目录', dictValue: '0',}, {dictLabel: '菜单', dictValue: '1',}, {dictLabel: '按钮', dictValue: '2',}],
interfaceMethodOptions: [{dictLabel: 'GET', dictValue: 'GET',}, {dictLabel: 'POST', dictValue: 'POST',},
@ -283,7 +283,8 @@
//
queryParams: {
name: undefined,
visible: undefined
visible: undefined,
pageNum: 'all'
},
//
form: {},
@ -303,12 +304,12 @@
},
created() {
this.getList();
// this.getDicts("sys_show_hide").then(response => {
// this.visibleOptions = response.data.results;
// });
// this.getDicts("sys_normal_disable").then(response => {
// this.statusOptions = response.data;
// });
this.getDicts("sys_show_hide").then(response => {
this.visibleOptions = response.data.results;
});
this.getDicts("sys_normal_disable").then(response => {
this.statusOptions = response.data;
});
},
methods: {
//
@ -319,7 +320,7 @@
getList() {
this.loading = true;
listMenu(this.queryParams).then(response => {
this.menuList = this.handleTree(response.data.results, "id");
this.menuList = this.handleTree(response.data, "id");
this.loading = false;
});
},
@ -339,7 +340,7 @@
listMenu().then(response => {
this.menuOptions = [];
const menu = {id: 0, name: '主类目', children: []};
menu.children = this.handleTree(response.data.results, "id");
menu.children = this.handleTree(response.data, "id");
this.menuOptions.push(menu);
});
},

View File

@ -103,7 +103,7 @@
<el-table v-loading="loading" :data="roleList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="角色编号" prop="roleId" width="120" />
<el-table-column label="角色编号" prop="id" width="120" />
<el-table-column label="角色名称" prop="roleName" :show-overflow-tooltip="true" width="150" />
<el-table-column label="权限字符" prop="roleKey" :show-overflow-tooltip="true" width="150" />
<el-table-column label="显示顺序" prop="roleSort" width="100" />
@ -351,8 +351,8 @@ export default {
this.loading = true;
listRole(this.addDateRange(this.queryParams, this.dateRange)).then(
response => {
this.roleList = response.rows;
this.total = response.total;
this.roleList = response.data.results;
this.total = response.data.count;
this.loading = false;
}
);
@ -388,16 +388,16 @@ export default {
return checkedKeys;
},
/** 根据角色ID查询菜单树结构 */
getRoleMenuTreeselect(roleId) {
return roleMenuTreeselect(roleId).then(response => {
this.menuOptions = response.menus;
getRoleMenuTreeselect(id) {
return roleMenuTreeselect(id).then(response => {
this.menuOptions = this.handleTree(response.data.menus,'id');
return response;
});
},
/** 根据角色ID查询部门树结构 */
getRoleDeptTreeselect(roleId) {
return roleDeptTreeselect(roleId).then(response => {
this.deptOptions = response.depts;
getRoleDeptTreeselect(id) {
return roleDeptTreeselect(id).then(response => {
this.deptOptions = this.handleTree(response.data.depts,'id');
return response;
});
},
@ -409,7 +409,7 @@ export default {
cancelButtonText: "取消",
type: "warning"
}).then(function() {
return changeRoleStatus(row.roleId, row.status);
return changeRoleStatus(row.id, row.status);
}).then(() => {
this.msgSuccess(text + "成功");
}).catch(function() {
@ -436,13 +436,13 @@ export default {
this.deptExpand = true,
this.deptNodeAll = false,
this.form = {
roleId: undefined,
id: undefined,
roleName: undefined,
roleKey: undefined,
roleSort: 0,
status: "0",
menuIds: [],
deptIds: [],
menu: [],
dept: [],
menuCheckStrictly: true,
deptCheckStrictly: true,
remark: undefined
@ -462,7 +462,7 @@ export default {
},
//
handleSelectionChange(selection) {
this.ids = selection.map(item => item.roleId)
this.ids = selection.map(item => item.id)
this.single = selection.length!=1
this.multiple = !selection.length
},
@ -506,14 +506,14 @@ export default {
/** 修改按钮操作 */
handleUpdate(row) {
this.reset();
const roleId = row.roleId || this.ids
const roleMenu = this.getRoleMenuTreeselect(roleId);
getRole(roleId).then(response => {
const id = row.id || this.ids
const roleMenu = this.getRoleMenuTreeselect(id);
getRole(id).then(response => {
this.form = response.data;
this.open = true;
this.$nextTick(() => {
roleMenu.then(res => {
let checkedKeys = res.checkedKeys
let checkedKeys = res.data.checkedKeys
checkedKeys.forEach((v) => {
this.$nextTick(()=>{
this.$refs.menu.setChecked(v, true ,false);
@ -533,13 +533,13 @@ export default {
/** 分配数据权限操作 */
handleDataScope(row) {
this.reset();
const roleDeptTreeselect = this.getRoleDeptTreeselect(row.roleId);
getRole(row.roleId).then(response => {
const roleDeptTreeselect = this.getRoleDeptTreeselect(row.id);
getRole(row.id).then(response => {
this.form = response.data;
this.openDataScope = true;
this.$nextTick(() => {
roleDeptTreeselect.then(res => {
this.$refs.dept.setCheckedKeys(res.checkedKeys);
this.$refs.dept.setCheckedKeys(res.data.checkedKeys);
});
});
this.title = "分配数据权限";
@ -549,15 +549,15 @@ export default {
submitForm: function() {
this.$refs["form"].validate(valid => {
if (valid) {
if (this.form.roleId != undefined) {
this.form.menuIds = this.getMenuAllCheckedKeys();
if (this.form.id != undefined) {
this.form.menu = this.getMenuAllCheckedKeys();
updateRole(this.form).then(response => {
this.msgSuccess("修改成功");
this.open = false;
this.getList();
});
} else {
this.form.menuIds = this.getMenuAllCheckedKeys();
this.form.menu = this.getMenuAllCheckedKeys();
addRole(this.form).then(response => {
this.msgSuccess("新增成功");
this.open = false;
@ -569,8 +569,8 @@ export default {
},
/** 提交按钮(数据权限) */
submitDataScope: function() {
if (this.form.roleId != undefined) {
this.form.deptIds = this.getDeptAllCheckedKeys();
if (this.form.id != undefined) {
this.form.dept = this.getDeptAllCheckedKeys();
dataScope(this.form).then(response => {
this.msgSuccess("修改成功");
this.openDataScope = false;
@ -580,7 +580,7 @@ export default {
},
/** 删除按钮操作 */
handleDelete(row) {
const roleIds = row.roleId || this.ids;
const roleIds = row.id || this.ids;
this.$confirm('是否确认删除角色编号为"' + roleIds + '"的数据项?', "警告", {
confirmButtonText: "确定",
cancelButtonText: "取消",