修正了切换角色功能

This commit is contained in:
TermiNexus committed 2026-08-02 19:09:23 +08:00
1 parent f062fb1e29
commit 15bcb072f9
3 files changed
+64 -19

No files matched your search

+17 -3
View File
@@ -36,9 +36,23 @@ export const refreshToken = (): Promise<{ AccessToken: string }> => {
return post<{ AccessToken: string }>('/Auth/RefreshToken')
}
/** 获取当前用户角色列表 */
export const getUserRoles = (): Promise<string[]> => {
return get<string[]>('/Auth/GetUserRoles')
/** 角色项(后端 GetUserRoles 返回的元素结构) */
export interface RoleItem {
RoleUUID?: string
RoleName: string
RoleStatus?: string | number
AssignScope?: string
RoleDesc?: string
CompanyName?: string
CompanyShort?: string
CompanyUUID?: string
/** 是否为当前激活角色 */
active?: boolean
}
/** 获取当前用户角色列表(解包后端 data.roles 两层结构) */
export const getUserRoles = (): Promise<RoleItem[]> => {
return get<{ roles: RoleItem[] }>('/Auth/GetUserRoles').then((res) => res.roles || [])
}
/** 切换当前角色 */
+35 -9
View File
@@ -14,7 +14,7 @@ import { ElMessage } from 'element-plus'
import { useAppStore } from '@/stores/app'
import { useUserStore } from '@/stores/user'
import { useTabsStore } from '@/stores/tabs'
import { getAvatarUrl } from '@/api/auth'
import { getAvatarUrl, type RoleItem } from '@/api/auth'
import TabBar from '@/components/TabBar.vue'
import RouteProgress from '@/components/RouteProgress.vue'
import PageMask from '@/components/PageMask.vue'
@@ -55,14 +55,14 @@ onMounted(() => {
}
})
/** 切换身份/角色 */
async function handleSwitchRole(role: string): Promise<void> {
if (role === userStore.currentRole || roleSwitching.value) return
/** 切换身份/角色(role 为 RoleItem 对象) */
async function handleSwitchRole(role: RoleItem): Promise<void> {
if (role.RoleName === userStore.currentRole || roleSwitching.value) return
roleSwitching.value = true
try {
await userStore.switchRole(role)
tabsStore.reset()
ElMessage.success(`已切换到:${role}`)
ElMessage.success(`已切换到:${role.RoleName}`)
router.push('/dashboard')
} catch {
ElMessage.error('身份切换失败')
@@ -223,14 +223,14 @@ const isFaIcon = (icon: string | undefined | null): boolean => {
<div class="user-dropdown-roles-list">
<div
v-for="role in roles"
:key="role"
:key="role.RoleUUID || role.RoleName"
class="user-dropdown-role-item"
:class="{ active: role === userStore.currentRole }"
:class="{ active: role.RoleName === userStore.currentRole }"
@click="handleSwitchRole(role)"
>
<el-icon v-if="role === userStore.currentRole" class="role-check"><Check /></el-icon>
<el-icon v-if="role.RoleName === userStore.currentRole" class="role-check"><Check /></el-icon>
<el-icon v-else class="role-placeholder"><CircleCheck /></el-icon>
<span>{{ role }}</span>
<span>{{ role.RoleName }}</span>
<el-icon v-if="roleSwitching" class="is-loading role-loading"><Loading /></el-icon>
</div>
</div>
@@ -439,6 +439,9 @@ const isFaIcon = (icon: string | undefined | null): boolean => {
}
:deep(.el-menu) {
// min-width: 0 覆盖默认 min-width: 240px,允许跟随容器收缩到 64px
min-width: 0;
width: 100%;
border-right: none;
padding: 8px 0;
// 宽度跟随侧边栏平滑收缩
@@ -460,6 +463,11 @@ const isFaIcon = (icon: string | undefined | null): boolean => {
transition: opacity 0.25s ease;
}
// 一级菜单(有二级菜单的):覆盖 Element Plus 默认 min-width: 200px,允许跟随容器收缩
:deep(.el-sub-menu) {
min-width: 0;
}
// 二级菜单容器:折叠时高度平滑收起,展开侧边栏后恢复
// min-width: 0 允许其跟随容器收缩(否则默认 min-width: 200px 会撑住 sub-menu 宽度)
:deep(.el-menu--inline) {
@@ -473,6 +481,24 @@ const isFaIcon = (icon: string | undefined | null): boolean => {
// 注意:icon 保持与展开态完全相同的位置(padding/margin 不变),仅宽度收缩 + 文字淡出
&.collapsed {
width: 64px;
// 一级菜单(sub-menu)宽度锁定为容器宽
:deep(.el-sub-menu) {
width: 100%;
min-width: 0;
}
// sub-menu 标题:padding-left 与 el-menu-item 对齐(icon 原地不动),
// padding-right 收紧(默认 44px 为箭头预留,会撑破 64px)
:deep(.el-sub-menu__title) {
width: 100%;
min-width: 0;
padding-left: 20px;
padding-right: 20px;
}
// 二级菜单容器宽度锁定为容器宽
:deep(.el-menu--inline) {
width: 100%;
min-width: 0;
}
// 隐藏左侧指示条
:deep(.el-menu-item),
:deep(.el-sub-menu__title) {
+12 -7
View File
@@ -1,14 +1,14 @@
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
import type { UserInfo, MenuItem } from '@/types/api'
import { getCurrentUser, getUserRoles, switchRole as apiSwitchRole, login as apiLogin, logout as apiLogout, type LoginParams } from '@/api/auth'
import { getCurrentUser, getUserRoles, switchRole as apiSwitchRole, login as apiLogin, logout as apiLogout, type LoginParams, type RoleItem } from '@/api/auth'
import { getMenuList } from '@/api/menu'
/** 用户状态管理:当前登录用户、角色、菜单、权限 */
export const useUserStore = defineStore('user', () => {
// === 状态 ===
const userInfo = ref<UserInfo | null>(null)
const roles = ref<string[]>([])
const roles = ref<RoleItem[]>([])
const menus = ref<MenuItem[]>([])
const token = ref<string>('')
const loading = ref(false)
@@ -23,9 +23,10 @@ export const useUserStore = defineStore('user', () => {
try {
const raw = localStorage.getItem(CACHE_KEY)
if (!raw) return
const cached = JSON.parse(raw) as { userInfo?: UserInfo | null; menus?: MenuItem[] | null }
const cached = JSON.parse(raw) as { userInfo?: UserInfo | null; menus?: MenuItem[] | null; roles?: RoleItem[] | null }
if (cached.userInfo) userInfo.value = cached.userInfo
if (cached.menus) menus.value = cached.menus
if (cached.roles?.length) roles.value = cached.roles
} catch {
// 缓存损坏:清除避免反复解析失败
localStorage.removeItem(CACHE_KEY)
@@ -37,7 +38,7 @@ export const useUserStore = defineStore('user', () => {
try {
localStorage.setItem(
CACHE_KEY,
JSON.stringify({ userInfo: userInfo.value, menus: menus.value }),
JSON.stringify({ userInfo: userInfo.value, menus: menus.value, roles: roles.value }),
)
} catch {
// 写入失败(隐私模式/配额满):忽略,不影响功能
@@ -76,6 +77,7 @@ export const useUserStore = defineStore('user', () => {
await apiLogin(params)
await fetchUserInfo()
await fetchMenus()
await fetchRoles()
} finally {
loading.value = false
}
@@ -125,15 +127,18 @@ export const useUserStore = defineStore('user', () => {
}
/** 获取角色列表 */
async function fetchRoles(): Promise<string[]> {
async function fetchRoles(): Promise<RoleItem[]> {
const list = await getUserRoles()
roles.value = list
saveToCache()
return list
}
/** 切换当前角色(身份切换) */
async function switchRole(role: string): Promise<void> {
await apiSwitchRole(role)
async function switchRole(role: RoleItem | string): Promise<void> {
// 传对象时取 RoleName(后端 SwitchRole 期望角色名)
const roleName = typeof role === 'string' ? role : role.RoleName
await apiSwitchRole(roleName)
// 刷新用户信息和菜单(不同角色可能有不同菜单权限)
await fetchUserInfo()
await fetchMenus()