完善刷新页面展示bug
This commit is contained in:
@@ -116,7 +116,8 @@ import {
|
|||||||
closeAllTabs,
|
closeAllTabs,
|
||||||
toggleMainAsideCollapse as storeToggleCollapse,
|
toggleMainAsideCollapse as storeToggleCollapse,
|
||||||
toggleSubSider as storeToggleSubSider,
|
toggleSubSider as storeToggleSubSider,
|
||||||
initNavState
|
initNavState,
|
||||||
|
restoreNavState
|
||||||
} from '@/layouts/admin/store/adminNavStore.uts'
|
} from '@/layouts/admin/store/adminNavStore.uts'
|
||||||
import type { TabItem } from '@/layouts/admin/store/adminNavStore.uts'
|
import type { TabItem } from '@/layouts/admin/store/adminNavStore.uts'
|
||||||
|
|
||||||
@@ -418,10 +419,18 @@ onMounted(async () => {
|
|||||||
// #endif
|
// #endif
|
||||||
|
|
||||||
isAuthReady.value = true
|
isAuthReady.value = true
|
||||||
initNavState()
|
|
||||||
if (props.currentPage != '') {
|
// 第二段:尝试从 sessionStorage 恢复上次打开的页签状态
|
||||||
openRoute(props.currentPage as string)
|
// restoreNavState 会校验路由有效性和权限,过滤无效项后重建 tabs
|
||||||
|
const restored = restoreNavState()
|
||||||
|
if (!restored) {
|
||||||
|
// 首次打开 / 缓存为空 / 恢复失败 → 走默认初始化(只有首页tab)
|
||||||
|
initNavState()
|
||||||
|
if (props.currentPage != '') {
|
||||||
|
openRoute(props.currentPage as string)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
// restored=true 时,activeRouteId 已由 restoreNavState 正确设置,无需额外跳转
|
||||||
|
|
||||||
// 初始化窗口宽度
|
// 初始化窗口宽度
|
||||||
windowWidth.value = uni.getWindowInfo().windowWidth
|
windowWidth.value = uni.getWindowInfo().windowWidth
|
||||||
|
|||||||
@@ -14,6 +14,25 @@ import {
|
|||||||
import { addView, activeFullPath, visitedViews } from './tagsViewStore.uts'
|
import { addView, activeFullPath, visitedViews } from './tagsViewStore.uts'
|
||||||
import { hasAdminModuleAccess } from '@/layouts/admin/utils/role.uts'
|
import { hasAdminModuleAccess } from '@/layouts/admin/utils/role.uts'
|
||||||
|
|
||||||
|
// ============================================
|
||||||
|
// Tabs 持久化 keys(使用 sessionStorage,与 token 策略一致)
|
||||||
|
// sessionStorage 在同一标签页 F5 刷新后保留,关闭标签页后自动清除
|
||||||
|
// ============================================
|
||||||
|
const TAB_STORAGE_KEY = 'admin_opened_tabs'
|
||||||
|
const ACTIVE_ROUTE_KEY = 'admin_active_route'
|
||||||
|
const LAST_SUB_STORAGE_KEY = 'admin_last_sub_by_menu'
|
||||||
|
|
||||||
|
/** 将当前 tabs / activeRouteId / lastSubIdByMenu 写入 sessionStorage */
|
||||||
|
function persistNavState(): void {
|
||||||
|
// #ifdef H5
|
||||||
|
try {
|
||||||
|
sessionStorage.setItem(TAB_STORAGE_KEY, JSON.stringify(tabs.value))
|
||||||
|
sessionStorage.setItem(ACTIVE_ROUTE_KEY, activeRouteId.value)
|
||||||
|
sessionStorage.setItem(LAST_SUB_STORAGE_KEY, JSON.stringify(lastSubIdByMenu.value))
|
||||||
|
} catch (_) {}
|
||||||
|
// #endif
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 标签页类型
|
* 标签页类型
|
||||||
*/
|
*/
|
||||||
@@ -120,6 +139,9 @@ export function openRoute(routeId: string, addTab: boolean = true): void {
|
|||||||
// 添加到标签页
|
// 添加到标签页
|
||||||
if (addTab) {
|
if (addTab) {
|
||||||
addTabItem(route)
|
addTabItem(route)
|
||||||
|
} else {
|
||||||
|
// 即使不新增 tab,activeRouteId 变化了也要持久化
|
||||||
|
persistNavState()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -150,6 +172,9 @@ function addTabItem(route: RouteRecord): void {
|
|||||||
// 更新新版 TagsViewStore
|
// 更新新版 TagsViewStore
|
||||||
addView(route, route.path)
|
addView(route, route.path)
|
||||||
activeFullPath.value = route.path
|
activeFullPath.value = route.path
|
||||||
|
|
||||||
|
// 持久化到 sessionStorage
|
||||||
|
persistNavState()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -178,6 +203,8 @@ export function closeTab(tabId: string): void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
tabs.value.splice(index, 1)
|
tabs.value.splice(index, 1)
|
||||||
|
// 持久化
|
||||||
|
persistNavState()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -192,6 +219,8 @@ export function closeOtherTabs(keepTabId: string): void {
|
|||||||
if (!stillExists) {
|
if (!stillExists) {
|
||||||
openRoute(keepTabId, false)
|
openRoute(keepTabId, false)
|
||||||
}
|
}
|
||||||
|
// 持久化
|
||||||
|
persistNavState()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -205,6 +234,8 @@ export function closeAllTabs(): void {
|
|||||||
if (homeTab) {
|
if (homeTab) {
|
||||||
openRoute(homeTab.id, false)
|
openRoute(homeTab.id, false)
|
||||||
}
|
}
|
||||||
|
// 持久化
|
||||||
|
persistNavState()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -222,7 +253,7 @@ export function toggleSubSider(): void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 初始化导航状态
|
* 初始化导航状态(首次进入 / 恢复失败时的兜底)
|
||||||
* 在 AdminLayout 组件 onMounted 时调用
|
* 在 AdminLayout 组件 onMounted 时调用
|
||||||
*/
|
*/
|
||||||
export function initNavState(): void {
|
export function initNavState(): void {
|
||||||
@@ -244,6 +275,86 @@ export function initNavState(): void {
|
|||||||
openRoute('home_index', false)
|
openRoute('home_index', false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从 sessionStorage 恢复导航状态(F5刷新后调用)
|
||||||
|
* - 校验每个缓存 tab 的路由是否仍然存在
|
||||||
|
* - 校验是否仍有权限
|
||||||
|
* - 过滤无效项后重建 tabs
|
||||||
|
* - 恢复 activeRouteId 和菜单高亮
|
||||||
|
* @returns true=恢复成功,false=无有效缓存或恢复失败(调用方应走 initNavState 兜底)
|
||||||
|
*/
|
||||||
|
export function restoreNavState(): boolean {
|
||||||
|
// #ifdef H5
|
||||||
|
try {
|
||||||
|
const rawTabs = sessionStorage.getItem(TAB_STORAGE_KEY)
|
||||||
|
if (!rawTabs) return false
|
||||||
|
|
||||||
|
const savedTabs = JSON.parse(rawTabs) as TabItem[]
|
||||||
|
if (!Array.isArray(savedTabs) || savedTabs.length === 0) return false
|
||||||
|
|
||||||
|
// 校验并过滤:路由必须存在且有权限
|
||||||
|
const validTabs = savedTabs.filter(tab => {
|
||||||
|
const route = findRouteById(tab.id)
|
||||||
|
if (!route) return false // 路由已不存在(文件删除或路由表变更)
|
||||||
|
const moduleId = route.parentId ?? tab.id.split('_')[0]
|
||||||
|
return hasAdminModuleAccess(moduleId) // 检查权限
|
||||||
|
})
|
||||||
|
|
||||||
|
// 首页 tab 始终保留(防止全部被过滤后无处可去)
|
||||||
|
const homeRoute = findRouteById('home_index')
|
||||||
|
if (homeRoute && !validTabs.some(t => t.id === 'home_index')) {
|
||||||
|
validTabs.unshift({
|
||||||
|
id: homeRoute.id,
|
||||||
|
title: homeRoute.title,
|
||||||
|
path: homeRoute.path,
|
||||||
|
isAffix: homeRoute.isAffix || false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if (validTabs.length === 0) return false
|
||||||
|
|
||||||
|
// 重建 tabs
|
||||||
|
tabs.value = validTabs
|
||||||
|
validTabs.forEach(tab => {
|
||||||
|
const route = findRouteById(tab.id)
|
||||||
|
if (route) addView(route, route.path)
|
||||||
|
})
|
||||||
|
|
||||||
|
// 恢复 lastSubIdByMenu
|
||||||
|
try {
|
||||||
|
const rawLast = sessionStorage.getItem(LAST_SUB_STORAGE_KEY)
|
||||||
|
if (rawLast) {
|
||||||
|
lastSubIdByMenu.value = JSON.parse(rawLast) as Record<string, string>
|
||||||
|
}
|
||||||
|
} catch (_) {}
|
||||||
|
|
||||||
|
// 恢复 activeRouteId
|
||||||
|
const savedActive = sessionStorage.getItem(ACTIVE_ROUTE_KEY)
|
||||||
|
const activeIsValid = savedActive != null &&
|
||||||
|
findRouteById(savedActive) != null &&
|
||||||
|
validTabs.some(t => t.id === savedActive)
|
||||||
|
|
||||||
|
const targetId = activeIsValid ? savedActive! : validTabs[0].id
|
||||||
|
activeRouteId.value = targetId
|
||||||
|
activeFullPath.value = findRouteById(targetId)?.path ?? ''
|
||||||
|
|
||||||
|
const activeRoute = findRouteById(targetId)
|
||||||
|
if (activeRoute?.parentId) {
|
||||||
|
activeTopMenuId.value = activeRoute.parentId
|
||||||
|
} else {
|
||||||
|
activeTopMenuId.value = targetId.split('_')[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('[AdminNav] 已从缓存恢复导航状态, tabs:', validTabs.length, 'active:', targetId)
|
||||||
|
return true
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('[AdminNav] 恢复导航状态失败,将走默认初始化:', e)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据 currentPage 同步状态
|
* 根据 currentPage 同步状态
|
||||||
* 用于页面组件传入 currentPage prop 时的状态同步
|
* 用于页面组件传入 currentPage prop 时的状态同步
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { state, getCurrentUser } from '@/utils/store.uts'
|
import { state, getCurrentUser } from '@/utils/store.uts'
|
||||||
import { clearAdminRoleCache, refreshAdminRole } from './role.uts'
|
import { clearAdminRoleCache, refreshAdminRole } from './role.uts'
|
||||||
import supa from '@/components/supadb/aksupainstance.uts'
|
import supa, { supaReady } from '@/components/supadb/aksupainstance.uts'
|
||||||
|
|
||||||
let __isHandlingExpired = false
|
let __isHandlingExpired = false
|
||||||
|
|
||||||
@@ -51,6 +51,11 @@ export function handleSessionExpired(reason?: string) {
|
|||||||
*/
|
*/
|
||||||
export async function ensureAdminSession(): Promise<boolean> {
|
export async function ensureAdminSession(): Promise<boolean> {
|
||||||
try {
|
try {
|
||||||
|
// ① 等待 hydrateSessionFromStorage() 完成(从storage恢复token→异步网络请求)
|
||||||
|
// 必须在 getSession() 之前 await,否则刷新后 this.session 仍为 null,
|
||||||
|
// 会被误判为未登录并触发 handleSessionExpired。
|
||||||
|
try { await supaReady } catch (_) {}
|
||||||
|
|
||||||
const sessionInfo = supa.getSession()
|
const sessionInfo = supa.getSession()
|
||||||
if (sessionInfo.session == null) {
|
if (sessionInfo.session == null) {
|
||||||
console.warn('[AdminAuth] 没有发现凭证,要求重新登录')
|
console.warn('[AdminAuth] 没有发现凭证,要求重新登录')
|
||||||
|
|||||||
Reference in New Issue
Block a user