feat(auth): 补齐退出登录交互并改为真实退出
- 侧栏底部用户区改为按原型 #userMenu 展开的用户菜单 (个人信息 / 修改密码 / 退出登录),支持点击浮层外部与 Esc 收起 - 退出登录增加二次确认;确认后注销服务端会话并整页跳转回登录页, 确保 token / tokenExpiresAt / userInfo(含 permissions)与内存态一并清空 - clearSession() 重置跨账号内存态(院区列表与选中项), 否则 SPA 内退出后换账号,新账号会看到上一个账号的院区 - 新增只读的个人信息弹窗(后端暂无「修改本人资料」接口,不提供编辑入口) - 顺带修正 stores/login.ts 中被 prettier 判为不合规的缩进
This commit is contained in:
@@ -17,6 +17,7 @@ import type {
|
||||
PasswordChangeRequest,
|
||||
} from '@/types/auth'
|
||||
import { clearAuthStorage, readStoredAuthSession, saveAuthSession } from '@/utils/auth-storage'
|
||||
import { useAppStore } from '@/stores/app'
|
||||
|
||||
export const useLoginStore = defineStore('login', () => {
|
||||
const storedSession = readStoredAuthSession()
|
||||
@@ -48,36 +49,36 @@ export const useLoginStore = defineStore('login', () => {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 已下线菜单:后端菜单资源里仍然下发、但前端已经不再提供页面的菜单。
|
||||
*
|
||||
* 「系统管理 → 报表分析」(`/report/index`)已整体下线,后端菜单资源暂时无法同步下架,
|
||||
* 所以在前端统一屏蔽:侧边栏不展示,路由守卫也会把它当成无权限菜单重定向走,
|
||||
* 避免出现点进去只有「前端暂未接入组件」占位页的死链。
|
||||
* 后端下架该菜单资源后,这个集合可以删掉。
|
||||
*/
|
||||
const RETIRED_MENU_PATHS = new Set(['/report/index'])
|
||||
/**
|
||||
* 已下线菜单:后端菜单资源里仍然下发、但前端已经不再提供页面的菜单。
|
||||
*
|
||||
* 「系统管理 → 报表分析」(`/report/index`)已整体下线,后端菜单资源暂时无法同步下架,
|
||||
* 所以在前端统一屏蔽:侧边栏不展示,路由守卫也会把它当成无权限菜单重定向走,
|
||||
* 避免出现点进去只有「前端暂未接入组件」占位页的死链。
|
||||
* 后端下架该菜单资源后,这个集合可以删掉。
|
||||
*/
|
||||
const RETIRED_MENU_PATHS = new Set(['/report/index'])
|
||||
|
||||
function isRetiredMenu(menu: PermissionResourceNode) {
|
||||
return RETIRED_MENU_PATHS.has(menu.routePath?.replace(/\/$/, '') ?? '')
|
||||
}
|
||||
function isRetiredMenu(menu: PermissionResourceNode) {
|
||||
return RETIRED_MENU_PATHS.has(menu.routePath?.replace(/\/$/, '') ?? '')
|
||||
}
|
||||
|
||||
const accessibleMenus = computed(() =>
|
||||
(authorization.value?.navigation ?? [])
|
||||
.filter((directory) => directory.resourceType === 'DIR' && directory.status === 'ENABLED')
|
||||
.flatMap((directory) => directory.children ?? [])
|
||||
.filter((menu) => !isRetiredMenu(menu)),
|
||||
)
|
||||
const accessibleMenus = computed(() =>
|
||||
(authorization.value?.navigation ?? [])
|
||||
.filter((directory) => directory.resourceType === 'DIR' && directory.status === 'ENABLED')
|
||||
.flatMap((directory) => directory.children ?? [])
|
||||
.filter((menu) => !isRetiredMenu(menu)),
|
||||
)
|
||||
|
||||
/** 侧边栏用的导航树:结构与后端一致,只剔除已下线菜单(空目录由使用方过滤) */
|
||||
const visibleNavigation = computed(() =>
|
||||
(authorization.value?.navigation ?? [])
|
||||
.filter((directory) => directory.resourceType === 'DIR' && directory.status === 'ENABLED')
|
||||
.map((directory) => ({
|
||||
...directory,
|
||||
children: (directory.children ?? []).filter((menu) => !isRetiredMenu(menu)),
|
||||
})),
|
||||
)
|
||||
/** 侧边栏用的导航树:结构与后端一致,只剔除已下线菜单(空目录由使用方过滤) */
|
||||
const visibleNavigation = computed(() =>
|
||||
(authorization.value?.navigation ?? [])
|
||||
.filter((directory) => directory.resourceType === 'DIR' && directory.status === 'ENABLED')
|
||||
.map((directory) => ({
|
||||
...directory,
|
||||
children: (directory.children ?? []).filter((menu) => !isRetiredMenu(menu)),
|
||||
})),
|
||||
)
|
||||
|
||||
function menuForPath(path: string): PermissionResourceNode | null {
|
||||
const normalizedPath = path.replace(/\/$/, '') || '/'
|
||||
@@ -130,6 +131,9 @@ const visibleNavigation = computed(() =>
|
||||
authorizationSyncedAt = 0
|
||||
currentUserReady.value = false
|
||||
currentUserRequest = null
|
||||
// 会话结束后清掉跨账号的内存态(当前是院区列表与选中项),
|
||||
// 否则 SPA 内退出登录后换账号登录,新账号会看到上一个账号的院区。
|
||||
useAppStore().reset()
|
||||
}
|
||||
|
||||
async function login(payload: LoginRequest) {
|
||||
|
||||
Reference in New Issue
Block a user