fix(admin): 登录后完整菜单 + 刷新保持当前Tab
- navForRole: 持平台令牌(operator)即恒显示完整运营菜单,不再被残留园区凭据(isParkUser)误判为园区端 - 新增 useUrlTab: 选区同步到 ?tab= ,刷新/回退均保持 - 算力中心 compute 与 园区管理 park 的 Tab 改用受控值 useUrlTab
This commit is contained in:
+6
-4
@@ -70,15 +70,17 @@ export const NAV: NavGroup[] = [
|
||||
// 按当前身份角色过滤导航
|
||||
export function navForRole(role: string | null): NavGroup[] {
|
||||
const { isAuthed } = useAuth();
|
||||
// 平台管理方:恒显示完整运营管理导航(角色暂未加载时也按 operator 视作,避免「只见园区管理」)
|
||||
if (isAuthed && !isParkUser()) {
|
||||
const r = role || "operator";
|
||||
// 平台管理方:持平台令牌即恒显示完整运营管理导航。
|
||||
// 不再叠加 !isParkUser() —— 避免「本会话曾登录过园区端/残留园区凭据」导致登录后只见园区管理,
|
||||
// 只有刷新/重新拉取身份后才恢复。平台令牌存在即平台优先。
|
||||
if (isAuthed) {
|
||||
const r = role === "operator" ? role : "operator";
|
||||
return NAV.map((g) => ({
|
||||
...g,
|
||||
items: g.items.filter((i) => !i.roles || i.roles.includes(r)),
|
||||
})).filter((g) => g.items.length > 0);
|
||||
}
|
||||
// 园区端(园区账密登录,无平台角色):只显示园区管理(本园区)
|
||||
// 园区端(园区账密登录,无平台令牌):只显示园区管理(本园区)
|
||||
if (isParkUser()) {
|
||||
return [{ title: "园区管理", items: [{ to: "/park", label: "园区管理", icon: Building2 }] }];
|
||||
}
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
import * as React from "react";
|
||||
import { useSearchParams } from "react-router-dom";
|
||||
|
||||
/**
|
||||
* URL 驱动的 Tab 状态:把当前选中项同步到 ``?tab=``,刷新/回退均保持。
|
||||
* key 默认「tab」,可用 ``param`` 覆盖(如一页内多个 Tab 组)。
|
||||
*
|
||||
* 用法:
|
||||
* const [tab, setTab] = useUrlTab("screens");
|
||||
* <Tabs value={tab} onValueChange={setTab}>...
|
||||
*/
|
||||
export function useUrlTab(defaultKey: string, param = "tab"): [string, (v: string) => void] {
|
||||
const [searchParams, setSearchParams] = useSearchParams();
|
||||
const current = searchParams.get(param) || defaultKey;
|
||||
|
||||
const setTab = React.useCallback(
|
||||
(v: string) => {
|
||||
setSearchParams(
|
||||
(prev) => {
|
||||
const next = new URLSearchParams(prev);
|
||||
next.set(param, v);
|
||||
return next;
|
||||
},
|
||||
{ replace: true },
|
||||
);
|
||||
},
|
||||
[setSearchParams, param],
|
||||
);
|
||||
|
||||
return [current, setTab];
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import { Input } from "@/components/ui/input";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { Loader2 } from "lucide-react";
|
||||
import { computeApi } from "@/api/resources";
|
||||
import { useUrlTab } from "@/lib/useUrlTab";
|
||||
import ChannelsPage from "./channels";
|
||||
import StatsPage from "./stats";
|
||||
import ModelsPage from "./models";
|
||||
@@ -35,7 +36,7 @@ const TABS = [
|
||||
];
|
||||
|
||||
export default function ComputePage() {
|
||||
const [tab, setTab] = React.useState("overview");
|
||||
const [tab, setTab] = useUrlTab("overview", "tab");
|
||||
|
||||
return (
|
||||
<div>
|
||||
|
||||
@@ -3,6 +3,7 @@ import { Card, CardContent } from "@/components/ui/card";
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
|
||||
import { ParkTenantProvider, useParkTenant } from "./tenant-context";
|
||||
import { useUrlTab } from "@/lib/useUrlTab";
|
||||
import { TenantTab } from "./tenant-tab";
|
||||
import { ScreensTab } from "./screens-tab";
|
||||
import { ScreenTab } from "./screen-tab";
|
||||
@@ -35,13 +36,14 @@ function TenantBar() {
|
||||
|
||||
function ParkPageInner() {
|
||||
const { tenantId, isParkMode } = useParkTenant();
|
||||
const [tab, setTab] = useUrlTab(isParkMode ? "screens" : "tenant");
|
||||
return (
|
||||
<div>
|
||||
<PageHeader title="园区管理" description={isParkMode ? "园区端:管理本园区屏幕与数据" : "运营端:全园区管理(创建园区、配置各园区)"} />
|
||||
<TenantBar />
|
||||
<Card>
|
||||
<CardContent className="pt-4">
|
||||
<Tabs defaultValue={isParkMode ? "screens" : "tenant"}>
|
||||
<Tabs value={tab} onValueChange={setTab}>
|
||||
<TabsList>
|
||||
{!isParkMode && <TabsTrigger value="tenant">园区创建</TabsTrigger>}
|
||||
<TabsTrigger value="screens">屏幕管理</TabsTrigger>
|
||||
|
||||
Reference in New Issue
Block a user