feat: 切换角色
This commit is contained in:
42
frontend/src/components/layout/layout-header.vue
Normal file
42
frontend/src/components/layout/layout-header.vue
Normal 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>
|
41
frontend/src/components/layout/layout-info/layout-info.vue
Normal file
41
frontend/src/components/layout/layout-info/layout-info.vue
Normal 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>
|
69
frontend/src/components/layout/layout-info/select-role.vue
Normal file
69
frontend/src/components/layout/layout-info/select-role.vue
Normal 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>
|
@@ -1,7 +1,6 @@
|
||||
import { createRouter, createWebHistory } from "vue-router";
|
||||
import { message } from "ant-design-vue";
|
||||
import { userStore } from "@/stores/user";
|
||||
import { loadRouter } from "@/utils/loadCpn";
|
||||
|
||||
const routes = [
|
||||
{
|
||||
|
@@ -21,3 +21,11 @@ export function getMenus(rid) {
|
||||
url: `/role/${rid}/menu`,
|
||||
});
|
||||
}
|
||||
|
||||
// 修改用户信息
|
||||
export function selectRole(rid) {
|
||||
return request({
|
||||
url: `/user/role/${rid}`,
|
||||
method: "put",
|
||||
});
|
||||
}
|
||||
|
@@ -4,7 +4,7 @@ import { message } from "ant-design-vue";
|
||||
|
||||
import router from "@/router";
|
||||
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(
|
||||
"user",
|
||||
@@ -28,14 +28,13 @@ export const userStore = defineStore(
|
||||
userMenus.value = [];
|
||||
};
|
||||
|
||||
// 非setup语法时的actions
|
||||
const loginAction = async (data) => {
|
||||
// 1. 登录
|
||||
const res = await login(data);
|
||||
token.value = res.data.token;
|
||||
|
||||
/**
|
||||
* 获取用户信息 & 菜单路由
|
||||
* @param {*} uid 用户id
|
||||
*/
|
||||
const getUserData = async (uid) => {
|
||||
// 2. 获取用户信息
|
||||
const info = await getUserInfo(res.data.id);
|
||||
const info = await getUserInfo(uid);
|
||||
userInfo.value = info.data;
|
||||
|
||||
// 3. 获取权限信息
|
||||
@@ -55,7 +54,13 @@ export const userStore = defineStore(
|
||||
} else {
|
||||
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("登录成功.");
|
||||
};
|
||||
@@ -65,6 +70,13 @@ export const userStore = defineStore(
|
||||
loadRouter(userMenus.value);
|
||||
};
|
||||
|
||||
// 切换角色
|
||||
const userSelectRole = async (rid) => {
|
||||
await selectRole(rid);
|
||||
// 重新拿用户信息
|
||||
await getUserData(userInfo.value.id);
|
||||
};
|
||||
|
||||
return {
|
||||
token,
|
||||
accessToken,
|
||||
@@ -75,6 +87,7 @@ export const userStore = defineStore(
|
||||
$reset,
|
||||
loginAction,
|
||||
loadRoleRouter,
|
||||
userSelectRole,
|
||||
};
|
||||
},
|
||||
{
|
||||
|
@@ -25,7 +25,15 @@ export default (config) => {
|
||||
},
|
||||
(err) => {
|
||||
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);
|
||||
}
|
||||
);
|
||||
|
@@ -1,17 +1,15 @@
|
||||
<script setup>
|
||||
import { ref } from "vue";
|
||||
import router from "@/router";
|
||||
|
||||
import { userStore } from "@/stores/user";
|
||||
|
||||
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 logout = () => {
|
||||
store.$reset();
|
||||
router.push("/login");
|
||||
// header组件 折叠按钮事件 触发a-layout-sider折叠
|
||||
const changeSiderFold = (subValue) => {
|
||||
collapsed.value = subValue;
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -25,7 +23,7 @@ const logout = () => {
|
||||
<a-layout>
|
||||
<a-layout-header style="background: #fff; padding: 0">
|
||||
<!-- 页头 -->
|
||||
<a-button @click="logout">退出</a-button>
|
||||
<LayoutHeader @changeFold="changeSiderFold" />
|
||||
</a-layout-header>
|
||||
<!-- 面包屑 -->
|
||||
<a-layout-content
|
||||
|
Reference in New Issue
Block a user