feat: 切换角色

This commit is contained in:
zy7y 2022-09-14 00:39:19 +08:00
parent 9766950106
commit d79b39b7eb
18 changed files with 255 additions and 50 deletions

View File

@ -28,4 +28,3 @@ async def menu_put(pk: int, data: MenuIn) -> Response:
if await put_menu(pk, data) == 0: if await put_menu(pk, data) == 0:
return Response(code=400, msg="菜单不存在") return Response(code=400, msg="菜单不存在")
return Response() return Response()

View File

@ -4,10 +4,15 @@ from fastapi import Query
from core.utils import list_to_tree from core.utils import list_to_tree
from dbhelper.relation import role_assigned_menu from dbhelper.relation import role_assigned_menu
from dbhelper.role import (del_role, get_role, get_role_menus, get_roles, from dbhelper.role import (
new_role, put_role) del_role,
from schemas import (ListAll, Response, RoleIn, RoleInfo, RoleMenuIn, get_role,
RoleQuery, RoleRead) get_role_menus,
get_roles,
new_role,
put_role,
)
from schemas import ListAll, Response, RoleIn, RoleInfo, RoleMenuIn, RoleQuery, RoleRead
async def role_add(data: RoleIn) -> Response[RoleInfo]: async def role_add(data: RoleIn) -> Response[RoleInfo]:

View File

@ -1,8 +1,16 @@
from fastapi import Query from fastapi import Depends, Query
from starlette.requests import Request
from core.security import get_password_hash from core.security import check_token, get_password_hash
from dbhelper.user import (del_user, get_user, get_user_info, get_users, from dbhelper.user import (
insert_user, put_user) del_user,
get_user,
get_user_info,
get_users,
insert_user,
put_user,
select_role,
)
from schemas import Response, UserAdd, UserInfo, UserPut, UserQuery, UserRead from schemas import Response, UserAdd, UserInfo, UserPut, UserQuery, UserRead
from schemas.common import ListAll from schemas.common import ListAll
@ -63,3 +71,11 @@ async def user_put(pk: int, data: UserPut) -> Response:
if isinstance(result, int): if isinstance(result, int):
return Response(code=400, msg=f"角色不存在{result}") return Response(code=400, msg=f"角色不存在{result}")
return Response() return Response()
async def user_select_role(rid: int, user=Depends(check_token)):
"""用户切换角色"""
res = await select_role(user.id, rid)
if res == 0:
return Response(code=400, msg=f"角色不存在{res}")
return Response()

View File

@ -74,7 +74,7 @@ async def check_permissions(request: Request, user: UserModel = Depends(check_to
whitelist = [f"/user/{user.id}", f"/role/{active_rid}/menu"] whitelist = [f"/user/{user.id}", f"/role/{active_rid}/menu"]
flag = request.url.path in whitelist and request.method == "GET" flag = request.url.path in whitelist and request.method == "GET"
if flag: if flag:
return return user
api = request.url.path api = request.url.path
for k, v in request.path_params.items(): for k, v in request.path_params.items():

View File

@ -104,3 +104,9 @@ async def put_user(uid: int, data: UserPut):
await UserRoleModel.bulk_create( await UserRoleModel.bulk_create(
[UserRoleModel(uid=uid, **role.dict()) for role in roles] [UserRoleModel(uid=uid, **role.dict()) for role in roles]
) )
async def select_role(uid: int, rid: int):
"""用户切换角色"""
await UserRoleModel.filter(uid=uid, rid__not=rid).update(status=1)
return await UserRoleModel.filter(uid=uid, rid=rid).update(status=5)

Binary file not shown.

Binary file not shown.

View File

@ -4,10 +4,24 @@ from fastapi import Depends, routing
from controller.common import about, login from controller.common import about, login
from controller.menu import menu_add, menu_arr, menu_del, menu_put from controller.menu import menu_add, menu_arr, menu_del, menu_put
from controller.role import (assigned_menu, role_add, role_arr, role_del, from controller.role import (
role_has_menu, role_put, role_query) assigned_menu,
from controller.user import (user_add, user_arr, user_del, user_info, role_add,
user_list, user_put) role_arr,
role_del,
role_has_menu,
role_put,
role_query,
)
from controller.user import (
user_add,
user_arr,
user_del,
user_info,
user_list,
user_put,
user_select_role,
)
from core.security import check_permissions from core.security import check_permissions
@ -107,9 +121,7 @@ class Route(routing.APIRoute):
) )
has_perm = { has_perm = {"dependencies": [Depends(check_permissions)]}
# "dependencies": [Depends(check_permissions)]
}
routes = [ routes = [
Route.post("/login", endpoint=login, tags=["公共"], summary="登录"), Route.post("/login", endpoint=login, tags=["公共"], summary="登录"),
@ -129,6 +141,9 @@ routes = [
Route.post( Route.post(
"/user/query", endpoint=user_list, tags=["用户管理"], summary="用户列表查询", **has_perm "/user/query", endpoint=user_list, tags=["用户管理"], summary="用户列表查询", **has_perm
), ),
Route.put(
"/user/role/{rid}", endpoint=user_select_role, tags=["用户管理"], summary="用户切换角色"
),
# 角色管理, # 角色管理,
Route.get("/role", endpoint=role_arr, tags=["角色管理"], summary="角色列表", **has_perm), Route.get("/role", endpoint=role_arr, tags=["角色管理"], summary="角色列表", **has_perm),
Route.post("/role", endpoint=role_add, tags=["角色管理"], summary="角色新增", **has_perm), Route.post("/role", endpoint=role_add, tags=["角色管理"], summary="角色新增", **has_perm),

View File

@ -309,20 +309,6 @@ params = [
method="DELETE", method="DELETE",
).dict(), ).dict(),
), ),
(
"/menu",
MenuIn(
name="修改菜单",
meta={"icon": "Update"},
path=None,
type=2,
component=None,
pid=5,
identifier="menu:update",
api="/menu/{pk}",
method="PUT",
).dict(),
),
# 分配权限 # 分配权限
( (
"/role/assigned/menu", "/role/assigned/menu",

View File

@ -0,0 +1,42 @@
<script setup>
import { ref } from "vue";
import UserInfo from "@/components/layout/layout-info/layout-info.vue";
import { MenuUnfoldOutlined, MenuFoldOutlined } from "@ant-design/icons-vue";
//
const collapsed = ref(false);
const emits = defineEmits(["changeFold"]);
//
const clickMenuFold = () => {
collapsed.value = !collapsed.value;
//
emits("changeFold", collapsed.value);
};
</script>
<template>
<div class="header">
<menu-unfold-outlined
v-if="collapsed"
class="trigger"
@click="clickMenuFold"
/>
<menu-fold-outlined v-else class="trigger" @click="clickMenuFold" />
<UserInfo />
</div>
</template>
<style scoped>
.trigger {
margin-left: 16px;
font-size: 24px;
}
.right {
float: right;
margin-right: 16px;
font-size: 16px;
}
</style>

View File

@ -0,0 +1,41 @@
<script setup>
import { ref } from "vue";
import { useRouter } from "vue-router";
import { userStore } from "@/stores/user";
import SelectRole from "./select-role.vue";
const store = userStore();
const router = useRouter();
const roleChangeRef = ref();
const onClick = ({ key }) => {
if (key === "1") {
//
roleChangeRef.value?.showModal();
} else {
store.$reset();
router.push("/login");
}
};
</script>
<template>
<div class="right">
<a-dropdown>
<a class="ant-dropdown-link" @click.prevent>
{{ store.userInfo.nickname }} - {{ store.userInfo.roles[0].name }}
</a>
<template #overlay>
<a-menu @click="onClick">
<a-menu-item key="1">切换角色</a-menu-item>
<a-menu-item key="2">退出登录</a-menu-item>
</a-menu>
</template>
</a-dropdown>
<SelectRole ref="roleChangeRef" />
</div>
</template>
<style scoped></style>

View File

@ -0,0 +1,69 @@
<script setup>
import { ref, computed } from "vue";
import { userStore } from "@/stores/user";
const store = userStore();
const loading = ref(false);
const visible = ref(false);
const currentRoleId = ref(store.userInfo.roles[0].id);
//
const options = computed(() => {
return store.userInfo.roles.map((role) => ({
label: role.name,
value: role.id,
}));
});
const showModal = () => {
visible.value = true;
};
const handleOk = () => {
loading.value = true;
store.userSelectRole(currentRoleId.value);
setTimeout(() => {
loading.value = false;
visible.value = false;
}, 1000);
};
const handleCancel = () => {
visible.value = false;
};
defineExpose({
showModal,
});
</script>
<template>
<div class="select-role">
<a-modal v-model:visible="visible" title="切换角色" @ok="handleOk">
<template #footer>
<a-button key="back" @click="handleCancel">取消</a-button>
<a-button
key="submit"
type="primary"
:loading="loading"
@click="handleOk"
>确定</a-button
>
</template>
<span>选择角色</span>
<a-space direction="vertical">
<a-select
v-model:value="currentRoleId"
size="default"
style="width: 400px"
:options="options"
></a-select>
</a-space>
</a-modal>
</div>
</template>
<style scoped></style>

View File

@ -1,7 +1,6 @@
import { createRouter, createWebHistory } from "vue-router"; import { createRouter, createWebHistory } from "vue-router";
import { message } from "ant-design-vue"; import { message } from "ant-design-vue";
import { userStore } from "@/stores/user"; import { userStore } from "@/stores/user";
import { loadRouter } from "@/utils/loadCpn";
const routes = [ const routes = [
{ {

View File

@ -21,3 +21,11 @@ export function getMenus(rid) {
url: `/role/${rid}/menu`, url: `/role/${rid}/menu`,
}); });
} }
// 修改用户信息
export function selectRole(rid) {
return request({
url: `/user/role/${rid}`,
method: "put",
});
}

View File

@ -4,7 +4,7 @@ import { message } from "ant-design-vue";
import router from "@/router"; import router from "@/router";
import { loadRouter, loadDefaultMenu } from "@/utils/loadCpn"; import { loadRouter, loadDefaultMenu } from "@/utils/loadCpn";
import { getMenus, getUserInfo, login } from "@/service/user"; import { getMenus, getUserInfo, login, selectRole } from "@/service/user";
export const userStore = defineStore( export const userStore = defineStore(
"user", "user",
@ -28,14 +28,13 @@ export const userStore = defineStore(
userMenus.value = []; userMenus.value = [];
}; };
// 非setup语法时的actions /**
const loginAction = async (data) => { * 获取用户信息 & 菜单路由
// 1. 登录 * @param {*} uid 用户id
const res = await login(data); */
token.value = res.data.token; const getUserData = async (uid) => {
// 2. 获取用户信息 // 2. 获取用户信息
const info = await getUserInfo(res.data.id); const info = await getUserInfo(uid);
userInfo.value = info.data; userInfo.value = info.data;
// 3. 获取权限信息 // 3. 获取权限信息
@ -55,7 +54,13 @@ export const userStore = defineStore(
} else { } else {
router.push("/main"); router.push("/main");
} }
};
const loginAction = async (data) => {
// 1. 登录
const res = await login(data);
token.value = res.data.token;
await getUserData(res.data.id);
// 弹框提示登录成功 // 弹框提示登录成功
message.success("登录成功."); message.success("登录成功.");
}; };
@ -65,6 +70,13 @@ export const userStore = defineStore(
loadRouter(userMenus.value); loadRouter(userMenus.value);
}; };
// 切换角色
const userSelectRole = async (rid) => {
await selectRole(rid);
// 重新拿用户信息
await getUserData(userInfo.value.id);
};
return { return {
token, token,
accessToken, accessToken,
@ -75,6 +87,7 @@ export const userStore = defineStore(
$reset, $reset,
loginAction, loginAction,
loadRoleRouter, loadRoleRouter,
userSelectRole,
}; };
}, },
{ {

View File

@ -25,7 +25,15 @@ export default (config) => {
}, },
(err) => { (err) => {
userStore().isLoading = !userStore().isLoading; userStore().isLoading = !userStore().isLoading;
message.error(err); if (err.response.data?.msg) {
message.error(err.response.data.msg);
} else if (err.response.data?.detail) {
// 请求参数缺失
message.error(err.response.data?.detail[0].msg);
} else {
message.error(err.message);
}
return Promise.reject(err); return Promise.reject(err);
} }
); );

View File

@ -1,17 +1,15 @@
<script setup> <script setup>
import { ref } from "vue"; import { ref } from "vue";
import router from "@/router";
import { userStore } from "@/stores/user";
import SiderMenu from "@/components/layout/sider-menu.vue"; import SiderMenu from "@/components/layout/sider-menu.vue";
const store = userStore(); import LayoutHeader from "@/components/layout/layout-header.vue";
// a-ayout-sider
const collapsed = ref(false); const collapsed = ref(false);
const logout = () => { // header a-layout-sider
store.$reset(); const changeSiderFold = (subValue) => {
router.push("/login"); collapsed.value = subValue;
}; };
</script> </script>
@ -25,7 +23,7 @@ const logout = () => {
<a-layout> <a-layout>
<a-layout-header style="background: #fff; padding: 0"> <a-layout-header style="background: #fff; padding: 0">
<!-- 页头 --> <!-- 页头 -->
<a-button @click="logout">退出</a-button> <LayoutHeader @changeFold="changeSiderFold" />
</a-layout-header> </a-layout-header>
<!-- 面包屑 --> <!-- 面包屑 -->
<a-layout-content <a-layout-content