@@ -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:
|
||||
model = Role
|
||||
@@ -116,3 +122,23 @@ class RoleViewSet(CustomModelViewSet, FastCrudMixin,FieldPermissionMixin):
|
||||
create_serializer_class = RoleCreateUpdateSerializer
|
||||
update_serializer_class = RoleCreateUpdateSerializer
|
||||
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="更新成功")
|
||||
@@ -11,38 +11,56 @@
|
||||
<template #header>
|
||||
<div>
|
||||
当前授权角色:
|
||||
<el-tag>{{ RoleDrawer.roleName }}</el-tag>
|
||||
<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">
|
||||
<MenuTree />
|
||||
<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"><MenuBtn /></el-tab-pane>
|
||||
<el-tab-pane label="列字段权限" name="second"><MenuField /></el-tab-pane>
|
||||
<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 MenuTree = defineAsyncComponent(() => import('./RoleMenuTree.vue'));
|
||||
const MenuBtn = defineAsyncComponent(() => import('./RoleMenuBtn.vue'));
|
||||
const MenuField = defineAsyncComponent(() => import('./RoleMenuField.vue'));
|
||||
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>
|
||||
|
||||
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>
|
||||
@@ -86,3 +86,36 @@ export function getRoleToDeptAll(query: object) {
|
||||
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,7 +1,7 @@
|
||||
<template>
|
||||
<fs-page>
|
||||
<fs-crud ref="crudRef" v-bind="crudBinding"> </fs-crud>
|
||||
<PermissionDrawerCom ref="PermissionDrawerCom" />
|
||||
<PermissionDrawerCom />
|
||||
</fs-page>
|
||||
</template>
|
||||
|
||||
@@ -12,12 +12,14 @@ import { createCrudOptions } from './crud';
|
||||
import { RoleDrawerStores } from './stores/RoleDrawerStores';
|
||||
import { RoleMenuBtnStores } from './stores/RoleMenuBtnStores';
|
||||
import { RoleMenuFieldStores } from './stores/RoleMenuFieldStores';
|
||||
import { RoleUsersStores } from './stores/RoleUsersStores';
|
||||
|
||||
const PermissionDrawerCom = defineAsyncComponent(() => import('./components/RoleDrawer.vue'));
|
||||
|
||||
const RoleDrawer = RoleDrawerStores(); // 权限配置抽屉参数
|
||||
const RoleDrawer = RoleDrawerStores(); // 角色-抽屉
|
||||
const RoleMenuBtn = RoleMenuBtnStores(); // 角色-菜单
|
||||
const RoleMenuField = RoleMenuFieldStores();
|
||||
const RoleMenuField = RoleMenuFieldStores();// 角色-菜单-字段
|
||||
const RoleUsers = RoleUsersStores();// 角色-用户
|
||||
const { crudBinding, crudRef, crudExpose } = useFs({
|
||||
createCrudOptions,
|
||||
context: { RoleDrawer, RoleMenuBtn, RoleMenuField },
|
||||
@@ -27,5 +29,8 @@ const { crudBinding, crudRef, crudExpose } = useFs({
|
||||
onMounted(async () => {
|
||||
// 刷新
|
||||
crudExpose.doRefresh();
|
||||
// 获取全部用户
|
||||
RoleUsers.get_all_users();
|
||||
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -7,6 +7,7 @@ const initialState: RoleDrawerType = {
|
||||
drawerVisible: false,
|
||||
roleId: undefined,
|
||||
roleName: undefined,
|
||||
users: [],
|
||||
};
|
||||
|
||||
export const RoleDrawerStores = defineStore('RoleDrawerStores', {
|
||||
@@ -19,8 +20,12 @@ export const RoleDrawerStores = defineStore('RoleDrawerStores', {
|
||||
*/
|
||||
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;
|
||||
},
|
||||
/**
|
||||
* 关闭权限修改抽屉
|
||||
|
||||
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);
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -16,6 +16,15 @@ export interface RoleItemType {
|
||||
creator: string;
|
||||
}
|
||||
|
||||
export interface UsersType {
|
||||
id: string | number;
|
||||
name: string;
|
||||
}
|
||||
export interface RoleUsersType {
|
||||
all_users: UsersType[];
|
||||
right_users: UsersType[];
|
||||
}
|
||||
|
||||
/**
|
||||
* 权限配置 抽屉组件参数数据类型
|
||||
*/
|
||||
@@ -26,6 +35,8 @@ export interface RoleDrawerType {
|
||||
roleId: string | number | undefined;
|
||||
/** 角色名称*/
|
||||
roleName: string | undefined;
|
||||
/** 用户*/
|
||||
users: UsersType[];
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user