fix: frontend routes
This commit is contained in:
@@ -4,6 +4,8 @@ import Icon from "../../components/common/Icon";
|
||||
import { UserManagementPage } from "../../components/admin/UserManagementPage";
|
||||
import { ProjectManagementPage } from "../../components/admin/ProjectManagementPage";
|
||||
|
||||
import "../../styles/admin.css";
|
||||
|
||||
export function SystemAdminPage({
|
||||
onNotify,
|
||||
onConnectionChange,
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
import { useScriptWorkspaceStore } from "../platform/state/scriptWorkspaceStore";
|
||||
import { useUiStore } from "../platform/state/uiStore";
|
||||
import { SystemAdminPage } from "./SystemAdminPage";
|
||||
|
||||
export default function SystemAdminRoute() {
|
||||
const setApiOnline = useScriptWorkspaceStore((s) => s.setApiOnline);
|
||||
const pushToast = useUiStore((s) => s.pushToast);
|
||||
|
||||
return (
|
||||
<SystemAdminPage
|
||||
onNotify={pushToast}
|
||||
onConnectionChange={setApiOnline}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -3,8 +3,6 @@ import { useNavigate } from "react-router";
|
||||
import { DashboardPage } from "../../components/admin/DashboardPage";
|
||||
import { useScriptWorkspaceStore } from "./state/scriptWorkspaceStore";
|
||||
|
||||
import "../../styles/dashboard.css";
|
||||
|
||||
export default function DashboardRoute() {
|
||||
const scripts = useScriptWorkspaceStore((s) => s.scripts);
|
||||
const apiOnline = useScriptWorkspaceStore((s) => s.apiOnline);
|
||||
|
||||
@@ -1,122 +0,0 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { Outlet, useLocation, useNavigate } from "react-router";
|
||||
|
||||
import { Sidebar } from "../../components/common/Sidebar";
|
||||
import { Toast } from "../../components/common/Toast";
|
||||
import { Topbar } from "../../components/common/Topbar";
|
||||
import { useApi, useAuth } from "../../context/AuthContext";
|
||||
import { useEditSessionLifecycle } from "./hooks/useEditSessionLifecycle";
|
||||
import {
|
||||
bindScriptWorkspaceApi,
|
||||
editSessionHandle,
|
||||
useScriptWorkspaceStore,
|
||||
} from "./state/scriptWorkspaceStore";
|
||||
import { useUiStore } from "./state/uiStore";
|
||||
|
||||
import "../../styles/platform.css";
|
||||
|
||||
type ActivePage = "home" | "scripts" | "schedules" | "system";
|
||||
|
||||
function pageFromPath(pathname: string): ActivePage {
|
||||
const page = pathname.replace(/^\/+|\/+$/g, "");
|
||||
return ["scripts", "schedules", "system"].includes(page)
|
||||
? (page as ActivePage)
|
||||
: "home";
|
||||
}
|
||||
|
||||
function pathForPage(page: ActivePage): string {
|
||||
return page === "home" ? "/workbench" : `/${page}`;
|
||||
}
|
||||
|
||||
export default function ModelPlatformApp() {
|
||||
const { currentWorkspace } = useAuth();
|
||||
if (!currentWorkspace) {
|
||||
return (
|
||||
<div
|
||||
className="app-shell"
|
||||
style={{ display: "flex", alignItems: "center", justifyContent: "center" }}
|
||||
>
|
||||
<div style={{ textAlign: "center" }}>
|
||||
<span style={{ fontSize: 18 }}>加载中…</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return <AuthenticatedLayout />;
|
||||
}
|
||||
|
||||
function AuthenticatedLayout() {
|
||||
const api = useApi();
|
||||
const location = useLocation();
|
||||
const navigate = useNavigate();
|
||||
const activePage = pageFromPath(location.pathname);
|
||||
const auth = useAuth();
|
||||
const {
|
||||
user,
|
||||
workspaces,
|
||||
currentWorkspace,
|
||||
setCurrentWorkspace,
|
||||
logout,
|
||||
} = auth;
|
||||
|
||||
const apiOnline = useScriptWorkspaceStore((s) => s.apiOnline);
|
||||
const endEditing = useScriptWorkspaceStore((s) => s.endEditing);
|
||||
const selectScript = useScriptWorkspaceStore((s) => s.selectScript);
|
||||
|
||||
const toast = useUiStore((s) => s.toast);
|
||||
const dismissToast = useUiStore((s) => s.dismissToast);
|
||||
const workspaceMenuOpen = useUiStore((s) => s.workspaceMenuOpen);
|
||||
const setWorkspaceMenuOpen = useUiStore((s) => s.setWorkspaceMenuOpen);
|
||||
|
||||
const [sidebarCollapsed, setSidebarCollapsed] = useState(false);
|
||||
|
||||
// 绑定 api 到 script workspace store
|
||||
useEffect(() => {
|
||||
bindScriptWorkspaceApi(api);
|
||||
return () => {
|
||||
bindScriptWorkspaceApi(null);
|
||||
};
|
||||
}, [api]);
|
||||
|
||||
// 心跳 / cleanup / 切页结束编辑 / 卸载前释放
|
||||
useEditSessionLifecycle({ activePage });
|
||||
|
||||
// toast 自动消失
|
||||
useEffect(() => {
|
||||
if (!toast) return;
|
||||
const timer = window.setTimeout(dismissToast, 3200);
|
||||
return () => window.clearTimeout(timer);
|
||||
}, [toast, dismissToast]);
|
||||
|
||||
return (
|
||||
<div className="app-shell">
|
||||
<Sidebar
|
||||
activePage={activePage}
|
||||
collapsed={sidebarCollapsed}
|
||||
onNavigate={(page) => navigate(pathForPage(page))}
|
||||
onToggleCollapse={() => setSidebarCollapsed((v) => !v)}
|
||||
onEndEditing={() => void endEditing(true)}
|
||||
onSelectScript={selectScript}
|
||||
editSessionRef={editSessionHandle}
|
||||
/>
|
||||
|
||||
<main className="main-area">
|
||||
<Topbar
|
||||
activePage={activePage}
|
||||
apiOnline={apiOnline}
|
||||
user={user}
|
||||
currentWorkspace={currentWorkspace!}
|
||||
workspaces={workspaces}
|
||||
workspaceMenuOpen={workspaceMenuOpen}
|
||||
onSetWorkspaceMenuOpen={setWorkspaceMenuOpen}
|
||||
onSetCurrentWorkspace={setCurrentWorkspace}
|
||||
onLogout={logout}
|
||||
/>
|
||||
|
||||
<Outlet />
|
||||
</main>
|
||||
|
||||
<Toast toast={toast} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
import { Navigate } from "react-router";
|
||||
|
||||
/**
|
||||
* 根路径 "/" 命中时直接跳到 /workbench。
|
||||
* 抽出独立文件是为了不和 route("workbench", ...) 撞 route id
|
||||
* (React Router v8 基于文件路径生成 id, 同一文件不能被两个路由引用)。
|
||||
*/
|
||||
export default function RootIndex() {
|
||||
return <Navigate to="/workbench" replace />;
|
||||
}
|
||||
Reference in New Issue
Block a user