fix(frontend): 菜单点击偶发无响应三处根因——①路由懒加载chunk失败被静默吞掉(新增onError自动整页重载+保险丝防循环) ②首页入口被权限接口阻塞(改乐观显示+缓存TTL10分钟+超时30s→8s) ③菜单hover预取目标页chunk(工具卡片/工作流步骤/顶部导航)

This commit is contained in:
2026-09-09 18:53:34 +08:00
parent 83cb3ff84e
commit 0cf20527a4
6 changed files with 139 additions and 14 deletions
@@ -37,6 +37,40 @@ function getAppPermissionCacheKey(uid: number) {
return `app_column_permissions:${String(uid)}`
}
/** 权限缓存有效期:10 分钟内直接用本地缓存渲染菜单/入口,避免接口慢时入口消失 */
const PERMISSION_CACHE_TTL_MS = 10 * 60 * 1000
interface CachedAppPermissions {
ts: number
items: PermissionMenuItem[]
}
/**
* 读取本地缓存的权限菜单项(兼容旧版纯数组格式:无时间戳视为长期有效)。
* 接口失败/超时时由调用方用它兜底,保证菜单不因权限接口抖动而消失。
*/
export function readCachedAppColumnPermissions(uid: number): PermissionMenuItem[] | null {
try {
const raw = window.localStorage.getItem(getAppPermissionCacheKey(uid)) || ''
if (!raw) return null
const parsed: unknown = JSON.parse(raw)
if (Array.isArray(parsed)) {
return parsed as PermissionMenuItem[]
}
if (
parsed &&
typeof parsed === 'object' &&
Array.isArray((parsed as CachedAppPermissions).items) &&
Date.now() - Number((parsed as CachedAppPermissions).ts || 0) < PERMISSION_CACHE_TTL_MS
) {
return (parsed as CachedAppPermissions).items
}
return null
} catch {
return null
}
}
function getAuthToken() {
return typeof window === 'undefined' ? '' : window.localStorage.getItem('aiimage_auth_token') || ''
}
@@ -70,6 +104,8 @@ async function fetchAppColumnPermissions() {
{
params: { menuType: 'app' },
headers,
// 权限接口只决定菜单显隐:8s 未返回即失败走缓存兜底,避免入口区长时间空白
timeout: 8000,
},
)
@@ -79,7 +115,7 @@ async function fetchAppColumnPermissions() {
const items = res.data || res.items || []
try {
window.localStorage.setItem(cacheKey, JSON.stringify(items))
window.localStorage.setItem(cacheKey, JSON.stringify({ ts: Date.now(), items }))
} catch (_error) {}
return items