From 9bbd11cc867bf05d355a92ef53b2beb0642eeac4 Mon Sep 17 00:00:00 2001 From: kkfluous Date: Thu, 30 Apr 2026 14:25:30 +0800 Subject: [PATCH] =?UTF-8?q?fix(feedback):=20=E5=8F=8D=E9=A6=88=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E8=B7=B3=E8=BD=AC=E6=97=A0=E6=95=88=20+=20=E6=9C=AC?= =?UTF-8?q?=E5=9C=B0=E8=B0=83=E8=AF=95=E8=A7=92=E8=89=B2=E8=A1=A5=E9=BD=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 问题 1:菜单点「反馈管理」跳到 #/admin/feedback,URL 变了但 AuthGate 只在初始 render 读 location,hashchange 不会重渲染。 修复:AuthGate 用 useState/useEffect 监听 hashchange/popstate, URL 变化即时切换页面。 问题 2:本地 DEV_BYPASS_AUTH 模式下 roles 没有 BI-ADMIN-FEEDBACK, 菜单看不到入口。前后端 dev bypass 的 roles 都补上: ['所有权限', 'BI-SCHEDULE-OPT', 'BI-ADMIN-FEEDBACK'] Co-Authored-By: Claude Opus 4.7 (1M context) --- src/App.tsx | 35 ++++++++++++++++++++++++----------- src/auth/AuthProvider.tsx | 2 +- src/server/auth/middleware.ts | 2 +- 3 files changed, 26 insertions(+), 13 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index 26880b1..a574898 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,4 +1,4 @@ -import { useMemo } from 'react'; +import { useEffect, useMemo, useState } from 'react'; import { Truck, Route, Activity, Zap } from 'lucide-react'; import { Shell, type ModuleConfig } from './components/Shell'; import AssetsModule from './modules/assets/AssetsModule'; @@ -22,8 +22,29 @@ const SCHEDULING_MODULE: ModuleConfig = { id: 'scheduling', label: '智能调度', icon: Activity, component: SchedulingModule, }; +function getRouteKey(): string { + if (typeof window === 'undefined') return ''; + const path = window.location.pathname; + const hash = window.location.hash; + if (path === '/ele/import' || hash === '#/ele/import' || hash === '#ele/import') return 'ele/import'; + if (path === '/admin/feedback' || hash === '#/admin/feedback' || hash === '#admin/feedback') return 'admin/feedback'; + return ''; +} + function AuthGate() { const { isLoading, isAuthenticated, error, user } = useAuth(); + const [routeKey, setRouteKey] = useState(getRouteKey); + + // 监听 hashchange / popstate,让 a href="#/..." 跳转能即时生效 + useEffect(() => { + const update = () => setRouteKey(getRouteKey()); + window.addEventListener('hashchange', update); + window.addEventListener('popstate', update); + return () => { + window.removeEventListener('hashchange', update); + window.removeEventListener('popstate', update); + }; + }, []); const modules = useMemo(() => { if (canAccessScheduling(user?.roles)) { @@ -48,16 +69,8 @@ function AuthGate() { } // 隐藏后端管理页:通过路径或 hash 直接访问,主导航不出现 - if (typeof window !== 'undefined') { - const path = window.location.pathname; - const hash = window.location.hash; - if (path === '/ele/import' || hash === '#/ele/import' || hash === '#ele/import') { - return ; - } - if (path === '/admin/feedback' || hash === '#/admin/feedback' || hash === '#admin/feedback') { - return ; - } - } + if (routeKey === 'ele/import') return ; + if (routeKey === 'admin/feedback') return ; return ; } diff --git a/src/auth/AuthProvider.tsx b/src/auth/AuthProvider.tsx index 0a7f3fd..4b5d398 100644 --- a/src/auth/AuthProvider.tsx +++ b/src/auth/AuthProvider.tsx @@ -46,7 +46,7 @@ export default function AuthProvider({ children }: { children: ReactNode }) { userName: '本地开发', permissionLevel: 'full', depName: '', - roles: ['所有权限', 'BI-SCHEDULE-OPT'], + roles: ['所有权限', 'BI-SCHEDULE-OPT', 'BI-ADMIN-FEEDBACK'], }, error: null, }); diff --git a/src/server/auth/middleware.ts b/src/server/auth/middleware.ts index a535b2d..fd2eefd 100644 --- a/src/server/auth/middleware.ts +++ b/src/server/auth/middleware.ts @@ -23,7 +23,7 @@ export async function authMiddleware(c: Context, next: Next) { depCode: '', depName: '', permissionLevel: 'full', - roles: ['所有权限', 'BI-SCHEDULE-OPT'], + roles: ['所有权限', 'BI-SCHEDULE-OPT', 'BI-ADMIN-FEEDBACK'], }; c.set('user', devUser); return next();