59 行
1.8 KiB
TypeScript
59 行
1.8 KiB
TypeScript
import { useEffect } from "react";
|
|
import { Outlet, useLocation } from "react-router-dom";
|
|
import { NAV_ITEMS } from "../components/navigation/NavLinks";
|
|
import { ErrorBoundary } from "../components/common/ErrorBoundary";
|
|
import { Sidebar } from "../components/navigation/Sidebar";
|
|
import { Topbar } from "../components/navigation/Topbar";
|
|
import { writeRecentVisit } from "../lib/recentVisits";
|
|
|
|
const EXTRA_TITLE_ENTRIES = [
|
|
{ path: "/notifications", title: "通知中心" },
|
|
{ path: "/reimbursements/", title: "报销详情" },
|
|
{ path: "/workflow/tasks/", title: "审批详情" },
|
|
{ path: "/people/", title: "员工档案" },
|
|
];
|
|
|
|
function resolveVisitTitle(pathname: string) {
|
|
const candidates = [
|
|
...NAV_ITEMS.map((item) => ({ path: item.to, title: item.label })),
|
|
...EXTRA_TITLE_ENTRIES,
|
|
].sort((left, right) => right.path.length - left.path.length);
|
|
|
|
const matched = candidates.find((item) => pathname === item.path || pathname.startsWith(item.path));
|
|
if (matched) {
|
|
return matched.title;
|
|
}
|
|
|
|
return pathname === "/" ? "Portal" : pathname;
|
|
}
|
|
|
|
export function AppShellLayout() {
|
|
const location = useLocation();
|
|
|
|
useEffect(() => {
|
|
const pathname = location.pathname;
|
|
if (!pathname || pathname === "/login" || pathname.startsWith("/mobile/")) {
|
|
return;
|
|
}
|
|
writeRecentVisit(pathname, resolveVisitTitle(pathname));
|
|
}, [location.pathname]);
|
|
|
|
return (
|
|
<div className="flex min-h-screen bg-zinc-50">
|
|
<Sidebar />
|
|
|
|
<main className="flex-1 flex flex-col min-w-0 lg:ml-64">
|
|
<Topbar />
|
|
|
|
<div className="flex-1 p-4 sm:p-8">
|
|
<div className="layout-container max-w-none">
|
|
<ErrorBoundary>
|
|
<Outlet />
|
|
</ErrorBoundary>
|
|
</div>
|
|
</div>
|
|
</main>
|
|
</div>
|
|
);
|
|
}
|