修正了切换角色功能
This commit is contained in:
1 parent
f062fb1e29
commit
15bcb072f9
3 files changed
+64
-19
No files matched your search
+17
-3
@@ -36,9 +36,23 @@ export const refreshToken = (): Promise<{ AccessToken: string }> => {
|
|||||||
return post<{ AccessToken: string }>('/Auth/RefreshToken')
|
return post<{ AccessToken: string }>('/Auth/RefreshToken')
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 获取当前用户角色列表 */
|
/** 角色项(后端 GetUserRoles 返回的元素结构) */
|
||||||
export const getUserRoles = (): Promise<string[]> => {
|
export interface RoleItem {
|
||||||
return get<string[]>('/Auth/GetUserRoles')
|
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 || [])
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 切换当前角色 */
|
/** 切换当前角色 */
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import { ElMessage } from 'element-plus'
|
|||||||
import { useAppStore } from '@/stores/app'
|
import { useAppStore } from '@/stores/app'
|
||||||
import { useUserStore } from '@/stores/user'
|
import { useUserStore } from '@/stores/user'
|
||||||
import { useTabsStore } from '@/stores/tabs'
|
import { useTabsStore } from '@/stores/tabs'
|
||||||
import { getAvatarUrl } from '@/api/auth'
|
import { getAvatarUrl, type RoleItem } from '@/api/auth'
|
||||||
import TabBar from '@/components/TabBar.vue'
|
import TabBar from '@/components/TabBar.vue'
|
||||||
import RouteProgress from '@/components/RouteProgress.vue'
|
import RouteProgress from '@/components/RouteProgress.vue'
|
||||||
import PageMask from '@/components/PageMask.vue'
|
import PageMask from '@/components/PageMask.vue'
|
||||||
@@ -55,14 +55,14 @@ onMounted(() => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
/** 切换身份/角色 */
|
/** 切换身份/角色(role 为 RoleItem 对象) */
|
||||||
async function handleSwitchRole(role: string): Promise<void> {
|
async function handleSwitchRole(role: RoleItem): Promise<void> {
|
||||||
if (role === userStore.currentRole || roleSwitching.value) return
|
if (role.RoleName === userStore.currentRole || roleSwitching.value) return
|
||||||
roleSwitching.value = true
|
roleSwitching.value = true
|
||||||
try {
|
try {
|
||||||
await userStore.switchRole(role)
|
await userStore.switchRole(role)
|
||||||
tabsStore.reset()
|
tabsStore.reset()
|
||||||
ElMessage.success(`已切换到:${role}`)
|
ElMessage.success(`已切换到:${role.RoleName}`)
|
||||||
router.push('/dashboard')
|
router.push('/dashboard')
|
||||||
} catch {
|
} catch {
|
||||||
ElMessage.error('身份切换失败')
|
ElMessage.error('身份切换失败')
|
||||||
@@ -223,14 +223,14 @@ const isFaIcon = (icon: string | undefined | null): boolean => {
|
|||||||
<div class="user-dropdown-roles-list">
|
<div class="user-dropdown-roles-list">
|
||||||
<div
|
<div
|
||||||
v-for="role in roles"
|
v-for="role in roles"
|
||||||
:key="role"
|
:key="role.RoleUUID || role.RoleName"
|
||||||
class="user-dropdown-role-item"
|
class="user-dropdown-role-item"
|
||||||
:class="{ active: role === userStore.currentRole }"
|
:class="{ active: role.RoleName === userStore.currentRole }"
|
||||||
@click="handleSwitchRole(role)"
|
@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>
|
<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>
|
<el-icon v-if="roleSwitching" class="is-loading role-loading"><Loading /></el-icon>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -439,6 +439,9 @@ const isFaIcon = (icon: string | undefined | null): boolean => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
:deep(.el-menu) {
|
:deep(.el-menu) {
|
||||||
|
// min-width: 0 覆盖默认 min-width: 240px,允许跟随容器收缩到 64px
|
||||||
|
min-width: 0;
|
||||||
|
width: 100%;
|
||||||
border-right: none;
|
border-right: none;
|
||||||
padding: 8px 0;
|
padding: 8px 0;
|
||||||
// 宽度跟随侧边栏平滑收缩
|
// 宽度跟随侧边栏平滑收缩
|
||||||
@@ -460,6 +463,11 @@ const isFaIcon = (icon: string | undefined | null): boolean => {
|
|||||||
transition: opacity 0.25s ease;
|
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 宽度)
|
// min-width: 0 允许其跟随容器收缩(否则默认 min-width: 200px 会撑住 sub-menu 宽度)
|
||||||
:deep(.el-menu--inline) {
|
:deep(.el-menu--inline) {
|
||||||
@@ -473,6 +481,24 @@ const isFaIcon = (icon: string | undefined | null): boolean => {
|
|||||||
// 注意:icon 保持与展开态完全相同的位置(padding/margin 不变),仅宽度收缩 + 文字淡出
|
// 注意:icon 保持与展开态完全相同的位置(padding/margin 不变),仅宽度收缩 + 文字淡出
|
||||||
&.collapsed {
|
&.collapsed {
|
||||||
width: 64px;
|
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-menu-item),
|
||||||
:deep(.el-sub-menu__title) {
|
:deep(.el-sub-menu__title) {
|
||||||
|
|||||||
+12
-7
@@ -1,14 +1,14 @@
|
|||||||
import { defineStore } from 'pinia'
|
import { defineStore } from 'pinia'
|
||||||
import { ref, computed } from 'vue'
|
import { ref, computed } from 'vue'
|
||||||
import type { UserInfo, MenuItem } from '@/types/api'
|
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'
|
import { getMenuList } from '@/api/menu'
|
||||||
|
|
||||||
/** 用户状态管理:当前登录用户、角色、菜单、权限 */
|
/** 用户状态管理:当前登录用户、角色、菜单、权限 */
|
||||||
export const useUserStore = defineStore('user', () => {
|
export const useUserStore = defineStore('user', () => {
|
||||||
// === 状态 ===
|
// === 状态 ===
|
||||||
const userInfo = ref<UserInfo | null>(null)
|
const userInfo = ref<UserInfo | null>(null)
|
||||||
const roles = ref<string[]>([])
|
const roles = ref<RoleItem[]>([])
|
||||||
const menus = ref<MenuItem[]>([])
|
const menus = ref<MenuItem[]>([])
|
||||||
const token = ref<string>('')
|
const token = ref<string>('')
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
@@ -23,9 +23,10 @@ export const useUserStore = defineStore('user', () => {
|
|||||||
try {
|
try {
|
||||||
const raw = localStorage.getItem(CACHE_KEY)
|
const raw = localStorage.getItem(CACHE_KEY)
|
||||||
if (!raw) return
|
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.userInfo) userInfo.value = cached.userInfo
|
||||||
if (cached.menus) menus.value = cached.menus
|
if (cached.menus) menus.value = cached.menus
|
||||||
|
if (cached.roles?.length) roles.value = cached.roles
|
||||||
} catch {
|
} catch {
|
||||||
// 缓存损坏:清除避免反复解析失败
|
// 缓存损坏:清除避免反复解析失败
|
||||||
localStorage.removeItem(CACHE_KEY)
|
localStorage.removeItem(CACHE_KEY)
|
||||||
@@ -37,7 +38,7 @@ export const useUserStore = defineStore('user', () => {
|
|||||||
try {
|
try {
|
||||||
localStorage.setItem(
|
localStorage.setItem(
|
||||||
CACHE_KEY,
|
CACHE_KEY,
|
||||||
JSON.stringify({ userInfo: userInfo.value, menus: menus.value }),
|
JSON.stringify({ userInfo: userInfo.value, menus: menus.value, roles: roles.value }),
|
||||||
)
|
)
|
||||||
} catch {
|
} catch {
|
||||||
// 写入失败(隐私模式/配额满):忽略,不影响功能
|
// 写入失败(隐私模式/配额满):忽略,不影响功能
|
||||||
@@ -76,6 +77,7 @@ export const useUserStore = defineStore('user', () => {
|
|||||||
await apiLogin(params)
|
await apiLogin(params)
|
||||||
await fetchUserInfo()
|
await fetchUserInfo()
|
||||||
await fetchMenus()
|
await fetchMenus()
|
||||||
|
await fetchRoles()
|
||||||
} finally {
|
} finally {
|
||||||
loading.value = false
|
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()
|
const list = await getUserRoles()
|
||||||
roles.value = list
|
roles.value = list
|
||||||
|
saveToCache()
|
||||||
return list
|
return list
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 切换当前角色(身份切换) */
|
/** 切换当前角色(身份切换) */
|
||||||
async function switchRole(role: string): Promise<void> {
|
async function switchRole(role: RoleItem | string): Promise<void> {
|
||||||
await apiSwitchRole(role)
|
// 传对象时取 RoleName(后端 SwitchRole 期望角色名)
|
||||||
|
const roleName = typeof role === 'string' ? role : role.RoleName
|
||||||
|
await apiSwitchRole(roleName)
|
||||||
// 刷新用户信息和菜单(不同角色可能有不同菜单权限)
|
// 刷新用户信息和菜单(不同角色可能有不同菜单权限)
|
||||||
await fetchUserInfo()
|
await fetchUserInfo()
|
||||||
await fetchMenus()
|
await fetchMenus()
|
||||||
|
|||||||
Reference in new issue
Block a user