@@ -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="更新成功")
|
||||||
@@ -11,38 +11,56 @@
|
|||||||
<template #header>
|
<template #header>
|
||||||
<div>
|
<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>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<splitpanes class="default-theme" style="height: 100%">
|
<splitpanes class="default-theme" style="height: 100%">
|
||||||
<pane min-size="20" size="22">
|
<pane min-size="20" size="22">
|
||||||
<div class="pane-box">
|
<div class="pane-box">
|
||||||
<MenuTree />
|
<MenuTreeCom />
|
||||||
</div>
|
</div>
|
||||||
</pane>
|
</pane>
|
||||||
<pane min-size="20">
|
<pane min-size="20">
|
||||||
<div class="pane-box">
|
<div class="pane-box">
|
||||||
<el-tabs v-model="activeName" class="demo-tabs">
|
<el-tabs v-model="activeName" class="demo-tabs">
|
||||||
<el-tab-pane label="接口权限" name="first"><MenuBtn /></el-tab-pane>
|
<el-tab-pane label="接口权限" name="first"><MenuBtnCom /></el-tab-pane>
|
||||||
<el-tab-pane label="列字段权限" name="second"><MenuField /></el-tab-pane>
|
<el-tab-pane label="列字段权限" name="second"><MenuFieldCom /></el-tab-pane>
|
||||||
</el-tabs>
|
</el-tabs>
|
||||||
</div>
|
</div>
|
||||||
</pane>
|
</pane>
|
||||||
</splitpanes>
|
</splitpanes>
|
||||||
</el-drawer>
|
</el-drawer>
|
||||||
|
|
||||||
|
<el-dialog v-model="dialogVisible" title="授权用户" width="700px" :close-on-click-modal="false">
|
||||||
|
<RoleUsersCom />
|
||||||
|
</el-dialog>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { Splitpanes, Pane } from 'splitpanes';
|
import { Splitpanes, Pane } from 'splitpanes';
|
||||||
import 'splitpanes/dist/splitpanes.css';
|
import 'splitpanes/dist/splitpanes.css';
|
||||||
|
import { UserFilled } from '@element-plus/icons-vue';
|
||||||
import { RoleDrawerStores } from '../stores/RoleDrawerStores';
|
import { RoleDrawerStores } from '../stores/RoleDrawerStores';
|
||||||
import { defineAsyncComponent, ref } from 'vue';
|
import { defineAsyncComponent, ref } from 'vue';
|
||||||
|
import { RoleUsersStores } from '../stores/RoleUsersStores';
|
||||||
|
|
||||||
const MenuTree = defineAsyncComponent(() => import('./RoleMenuTree.vue'));
|
const MenuTreeCom = defineAsyncComponent(() => import('./RoleMenuTree.vue'));
|
||||||
const MenuBtn = defineAsyncComponent(() => import('./RoleMenuBtn.vue'));
|
const MenuBtnCom = defineAsyncComponent(() => import('./RoleMenuBtn.vue'));
|
||||||
const MenuField = defineAsyncComponent(() => import('./RoleMenuField.vue'));
|
const MenuFieldCom = defineAsyncComponent(() => import('./RoleMenuField.vue'));
|
||||||
|
const RoleUsersCom = defineAsyncComponent(() => import('./RoleUsers.vue'));
|
||||||
const RoleDrawer = RoleDrawerStores(); // 抽屉参数
|
const RoleDrawer = RoleDrawerStores(); // 抽屉参数
|
||||||
|
const RoleUsers = RoleUsersStores(); // 角色-用户
|
||||||
const activeName = ref('first');
|
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>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<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,
|
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>
|
<template>
|
||||||
<fs-page>
|
<fs-page>
|
||||||
<fs-crud ref="crudRef" v-bind="crudBinding"> </fs-crud>
|
<fs-crud ref="crudRef" v-bind="crudBinding"> </fs-crud>
|
||||||
<PermissionDrawerCom ref="PermissionDrawerCom" />
|
<PermissionDrawerCom />
|
||||||
</fs-page>
|
</fs-page>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -12,20 +12,25 @@ import { createCrudOptions } from './crud';
|
|||||||
import { RoleDrawerStores } from './stores/RoleDrawerStores';
|
import { RoleDrawerStores } from './stores/RoleDrawerStores';
|
||||||
import { RoleMenuBtnStores } from './stores/RoleMenuBtnStores';
|
import { RoleMenuBtnStores } from './stores/RoleMenuBtnStores';
|
||||||
import { RoleMenuFieldStores } from './stores/RoleMenuFieldStores';
|
import { RoleMenuFieldStores } from './stores/RoleMenuFieldStores';
|
||||||
|
import { RoleUsersStores } from './stores/RoleUsersStores';
|
||||||
|
|
||||||
const PermissionDrawerCom = defineAsyncComponent(() => import('./components/RoleDrawer.vue'));
|
const PermissionDrawerCom = defineAsyncComponent(() => import('./components/RoleDrawer.vue'));
|
||||||
|
|
||||||
const RoleDrawer = RoleDrawerStores(); // 权限配置抽屉参数
|
const RoleDrawer = RoleDrawerStores(); // 角色-抽屉
|
||||||
const RoleMenuBtn = RoleMenuBtnStores(); // 角色-菜单
|
const RoleMenuBtn = RoleMenuBtnStores(); // 角色-菜单
|
||||||
const RoleMenuField = RoleMenuFieldStores();
|
const RoleMenuField = RoleMenuFieldStores();// 角色-菜单-字段
|
||||||
|
const RoleUsers = RoleUsersStores();// 角色-用户
|
||||||
const { crudBinding, crudRef, crudExpose } = useFs({
|
const { crudBinding, crudRef, crudExpose } = useFs({
|
||||||
createCrudOptions,
|
createCrudOptions,
|
||||||
context: { RoleDrawer, RoleMenuBtn,RoleMenuField },
|
context: { RoleDrawer, RoleMenuBtn, RoleMenuField },
|
||||||
});
|
});
|
||||||
|
|
||||||
// 页面打开后获取列表数据
|
// 页面打开后获取列表数据
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
// 刷新
|
// 刷新
|
||||||
crudExpose.doRefresh();
|
crudExpose.doRefresh();
|
||||||
|
// 获取全部用户
|
||||||
|
RoleUsers.get_all_users();
|
||||||
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ const initialState: RoleDrawerType = {
|
|||||||
drawerVisible: false,
|
drawerVisible: false,
|
||||||
roleId: undefined,
|
roleId: undefined,
|
||||||
roleName: undefined,
|
roleName: undefined,
|
||||||
|
users: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
export const RoleDrawerStores = defineStore('RoleDrawerStores', {
|
export const RoleDrawerStores = defineStore('RoleDrawerStores', {
|
||||||
@@ -19,8 +20,12 @@ export const RoleDrawerStores = defineStore('RoleDrawerStores', {
|
|||||||
*/
|
*/
|
||||||
handleDrawerOpen(row: any) {
|
handleDrawerOpen(row: any) {
|
||||||
this.drawerVisible = true;
|
this.drawerVisible = true;
|
||||||
|
this.set_state(row);
|
||||||
|
},
|
||||||
|
set_state(row: any) {
|
||||||
this.roleName = row.name;
|
this.roleName = row.name;
|
||||||
this.roleId = row.id;
|
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;
|
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;
|
roleId: string | number | undefined;
|
||||||
/** 角色名称*/
|
/** 角色名称*/
|
||||||
roleName: string | undefined;
|
roleName: string | undefined;
|
||||||
|
/** 用户*/
|
||||||
|
users: UsersType[];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -82,7 +93,7 @@ export interface RoleMenuFieldHeaderType {
|
|||||||
/** 模型表字段名 */
|
/** 模型表字段名 */
|
||||||
label: string;
|
label: string;
|
||||||
/** 字段显示名 */
|
/** 字段显示名 */
|
||||||
disabled: string ;
|
disabled: string;
|
||||||
/** 是否可查询 */
|
/** 是否可查询 */
|
||||||
checked: boolean;
|
checked: boolean;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user