Files
ttstd-infinite-canvas/web/src/router.tsx
ddCat 615974f1d9 feat(banner): 首页常驻滚动通知 - 合并 PR #531 到本地
将常驻通知迁移顺延为 v20-v22,避免与已发布的 v19 支付插件版本冲突。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-18 09:43:40 +08:00

222 lines
13 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { lazy, Suspense, type ReactNode } from "react";
import { createBrowserRouter, Navigate, Outlet, useLocation } from "react-router";
import { RequireAuth } from "@/components/auth/require-auth";
import { FullScreenLoader, WorkspaceRouteLoader } from "@/components/ui/aceternity/full-screen-loader";
import { loadAssetsPage, loadCanvasPage, loadCanvasProjectPage, loadCreatePage, loadProjectDetailPage, loadProjectsPage } from "@/lib/workspace-route-modules";
import { CanvasRefreshShell } from "@/pages/canvas/canvas-refresh-shell";
import { AuthScene } from "@/pages/auth/auth-scene";
import RouteErrorPage from "@/pages/route-error";
const AdminPage = lazy(() => import("@/pages/admin"));
const AnalyticsPage = lazy(() => import("@/pages/admin/admin-route-pages").then((module) => ({ default: module.AnalyticsPage })));
const AnnouncementsPage = lazy(() => import("@/pages/admin/admin-route-pages").then((module) => ({ default: module.AnnouncementsPage })));
const BannerAnnouncementsPage = lazy(() => import("@/pages/admin/admin-route-pages").then((module) => ({ default: module.BannerAnnouncementsPage })));
const StorageResourcesPage = lazy(() => import("@/pages/admin/admin-route-pages").then((module) => ({ default: module.StorageResourcesPage })));
const CreditOperationsPage = lazy(() => import("@/pages/admin/admin-route-pages").then((module) => ({ default: module.CreditOperationsPage })));
const AccessSettingsPage = lazy(() => import("@/pages/admin/admin-route-pages").then((module) => ({ default: module.AccessSettingsPage })));
const EmailSettingsPage = lazy(() => import("@/pages/admin/admin-route-pages").then((module) => ({ default: module.EmailSettingsPage })));
const FeatureAvailabilityPage = lazy(() => import("@/pages/admin/admin-route-pages").then((module) => ({ default: module.FeatureAvailabilityPage })));
const AgentLessonsPage = lazy(() => import("@/pages/admin/admin-route-pages").then((module) => ({ default: module.AgentLessonsPage })));
const ChannelsPage = lazy(() => import("@/pages/admin/channels/channels-page"));
const LogicalModelsPage = lazy(() => import("@/pages/admin/logical-models/logical-models-page"));
const AdminPluginsPage = lazy(() => import("@/pages/admin/plugins/plugins-page"));
const AdminPaymentsPage = lazy(() => import("@/pages/admin/payments/payments-page"));
const LogsPage = lazy(() => import("@/pages/admin/logs/logs-page"));
const RedemptionCodesPage = lazy(() => import("@/pages/admin/redemption-codes/redemption-codes-page"));
const RuntimePolicySettingsPage = lazy(() => import("@/pages/admin/settings/runtime-policy-settings-page"));
const AppearanceSettingsPage = lazy(() => import("@/pages/admin/settings/appearance-settings-page"));
const DrawingEngineSettingsPage = lazy(() => import("@/pages/admin/settings/drawing-engine-settings-page"));
const StorageSettingsPage = lazy(() => import("@/pages/admin/settings/storage-settings-page"));
const ArkPrivateAssetsSettingsPage = lazy(() => import("@/pages/admin/settings/ark-private-assets-settings-page"));
const ResponseInterceptionSettingsPage = lazy(() => import("@/pages/admin/settings/response-interception-settings-page"));
const ThirdPartySettingsPage = lazy(() => import("@/pages/admin/settings/libtv-settings-page"));
const SystemUpdatePage = lazy(() => import("@/pages/admin/settings/system-update-page"));
const SystemPerformancePage = lazy(() => import("@/pages/admin/settings/system-performance-page"));
const StoryboardPromptsPage = lazy(() => import("@/pages/admin/storyboard-prompts/storyboard-prompts-page"));
const UsersPage = lazy(() => import("@/pages/admin/users/users-page"));
const AssetsPage = lazy(loadAssetsPage);
const LoginPage = lazy(() => import("@/pages/auth/login"));
const RegisterPage = lazy(() => import("@/pages/auth/register"));
const ForgotPasswordPage = lazy(() => import("@/pages/auth/forgot-password"));
const CanvasPage = lazy(loadCanvasPage);
const CanvasProjectPage = lazy(loadCanvasProjectPage);
const SharedCanvasPage = lazy(() => import("@/pages/canvas/shared"));
const CreatePage = lazy(loadCreatePage);
const NotFound = lazy(() => import("@/pages/not-found"));
const SkillsPage = lazy(() => import("@/pages/skills"));
const PluginsPage = lazy(() => import("@/pages/plugins"));
const EagleLibraryPage = lazy(() => import("@/pages/plugins/eagle"));
const TasksPage = lazy(() => import("@/pages/tasks"));
const ProjectsPage = lazy(loadProjectsPage);
const ProjectDetailPage = lazy(loadProjectDetailPage);
const SettingsPage = lazy(() => import("@/pages/settings"));
const TestVoiceRecording = lazy(() => import("@/pages/test-voice-recording"));
const UserLayout = lazy(() => import("@/layouts/user-layout"));
const RequireFeature = lazy(() => import("@/components/auth/require-feature").then((module) => ({ default: module.RequireFeature })));
function deferred(element: ReactNode) {
return <Suspense fallback={<WorkspaceRouteLoader />}>{element}</Suspense>;
}
function fullScreenDeferred(element: ReactNode) {
return <Suspense fallback={<FullScreenLoader label="正在打开创作空间" detail="准备当前页面" />}>{element}</Suspense>;
}
function AuthenticatedWorkspaceLayout() {
const { pathname } = useLocation();
const isCanvasProjectRoute = pathname.startsWith("/canvas/");
const fallback = isCanvasProjectRoute ? <CanvasRefreshShell /> : <FullScreenLoader label="正在打开创作空间" detail="准备当前页面" />;
return <RequireAuth><Suspense fallback={fallback}><UserLayout><Outlet /></UserLayout></Suspense></RequireAuth>;
}
/**
* DEV 专用实验室路由。
*
* lazy(() => import(...)) 写在函数体内,而不是模块顶层常量:
* 生产构建时 import.meta.env.DEV 被替换为 false,本函数随之不可达,
* 摇树会连同其中的动态 import 一起删除,实验室代码不进入生产依赖图。
* 若把 lazy 提到模块顶层,动态 import 会被静态分析成真实 chunk 并打进 dist。
*/
function devRoutes() {
const FolderPreviewLab = lazy(() => import("@/pages/dev/folder-preview-lab"));
const DirectorReproLab = lazy(() => import("@/pages/dev/director-repro-lab"));
return [
{ path: "/dev/folders", element: fullScreenDeferred(<FolderPreviewLab />), errorElement: <RouteErrorPage /> },
{ path: "/dev/director-repro", element: fullScreenDeferred(<DirectorReproLab />), errorElement: <RouteErrorPage /> },
];
}
export const router = createBrowserRouter([
{
element: <AuthScene />,
errorElement: <RouteErrorPage />,
children: [
{ path: "/login", element: fullScreenDeferred(<LoginPage />) },
{ path: "/register", element: fullScreenDeferred(<RegisterPage />) },
{ path: "/forgot-password", element: fullScreenDeferred(<ForgotPasswordPage />) },
],
},
{ path: "/share/canvas/:token", element: fullScreenDeferred(<SharedCanvasPage />), errorElement: <RouteErrorPage /> },
...(import.meta.env.DEV ? devRoutes() : []),
{
element: <AuthenticatedWorkspaceLayout />,
errorElement: <RouteErrorPage />,
children: [
{ path: "/", element: <RequireAuth>{deferred(<CreatePage />)}</RequireAuth> },
{ path: "/create", element: <RequireAuth>{deferred(<CreatePage />)}</RequireAuth> },
{
path: "/tasks",
element: (
<RequireAuth>
<RequireFeature feature="taskCenterEnabled">{deferred(<TasksPage />)}</RequireFeature>
</RequireAuth>
),
},
{ path: "/assets", element: <RequireAuth>{deferred(<AssetsPage />)}</RequireAuth> },
{ path: "/skills", element: <RequireAuth>{deferred(<SkillsPage />)}</RequireAuth> },
{
path: "/plugins",
element: (
<RequireAuth>
<RequireFeature feature="pluginCenterEnabled">{deferred(<PluginsPage />)}</RequireFeature>
</RequireAuth>
),
},
{
path: "/plugins/eagle",
element: (
<RequireAuth>
<RequireFeature feature="pluginCenterEnabled">{deferred(<EagleLibraryPage />)}</RequireFeature>
</RequireAuth>
),
},
{
path: "/wallet",
element: <RequireAuth>{null}</RequireAuth>,
},
{ path: "/settings", element: <RequireAuth>{deferred(<SettingsPage />)}</RequireAuth> },
{ path: "/test-voice-recording", element: <RequireAuth>{deferred(<TestVoiceRecording />)}</RequireAuth> },
{
path: "/projects",
element: (
<RequireAuth>
<RequireFeature feature="shortDramaEnabled">{deferred(<ProjectsPage />)}</RequireFeature>
</RequireAuth>
),
},
{
path: "/projects/:projectId",
element: (
<RequireAuth>
<RequireFeature feature="shortDramaEnabled">{deferred(<ProjectDetailPage />)}</RequireFeature>
</RequireAuth>
),
},
{
path: "/projects/:projectId/:view",
element: (
<RequireAuth>
<RequireFeature feature="shortDramaEnabled">{deferred(<ProjectDetailPage />)}</RequireFeature>
</RequireAuth>
),
},
{
path: "/projects/:projectId/chapters/:chapterId",
element: (
<RequireAuth>
<RequireFeature feature="shortDramaEnabled">{deferred(<ProjectDetailPage />)}</RequireFeature>
</RequireAuth>
),
},
{
path: "/projects/:projectId/workflow/:unitId/:stage",
element: (
<RequireAuth>
<RequireFeature feature="shortDramaEnabled">{deferred(<ProjectDetailPage />)}</RequireFeature>
</RequireAuth>
),
},
{ path: "/canvas", element: <RequireAuth>{deferred(<CanvasPage />)}</RequireAuth> },
{ path: "/canvas/:id", element: <RequireAuth><CanvasProjectPage /></RequireAuth> },
{
path: "/admin",
element: <RequireAuth>{deferred(<AdminPage />)}</RequireAuth>,
children: [
{ index: true, element: <AnalyticsPage /> },
{ path: "users", element: <UsersPage /> },
{ path: "channels", element: <ChannelsPage /> },
{ path: "models", element: <RequireFeature feature="frontendModelsEnabled"><LogicalModelsPage /></RequireFeature> },
{ path: "plugins", element: <AdminPluginsPage /> },
{ path: "payments", element: <AdminPaymentsPage /> },
{ path: "prompt-templates", element: <StoryboardPromptsPage /> },
{ path: "storyboard-prompts", element: <Navigate to="/admin/prompt-templates" replace /> },
{ path: "announcements", element: <AnnouncementsPage /> },
{ path: "banner-announcements", element: <BannerAnnouncementsPage /> },
{ path: "agent-lessons", element: <AgentLessonsPage /> },
{ path: "resources", element: <StorageResourcesPage /> },
{ path: "credit-operations", element: <CreditOperationsPage /> },
{ path: "redemption-codes", element: <RedemptionCodesPage /> },
{ path: "logs", element: <LogsPage /> },
{ path: "settings", element: <Navigate to="runtime-policy" replace /> },
{ path: "settings/appearance", element: <AppearanceSettingsPage /> },
{ path: "settings/drawing-engine", element: <DrawingEngineSettingsPage /> },
{ path: "settings/concurrency", element: <Navigate to="/admin/settings/runtime-policy" replace /> },
{ path: "settings/runtime-policy", element: <RuntimePolicySettingsPage /> },
{ path: "settings/features", element: <FeatureAvailabilityPage /> },
{ path: "settings/access", element: <AccessSettingsPage /> },
{ path: "settings/email", element: <EmailSettingsPage /> },
{ path: "settings/storage", element: <StorageSettingsPage /> },
{ path: "settings/ark-private-assets", element: <ArkPrivateAssetsSettingsPage /> },
{ path: "settings/response-interception", element: <ResponseInterceptionSettingsPage /> },
{ path: "settings/third-party", element: <ThirdPartySettingsPage /> },
{ path: "settings/system-update", element: <SystemUpdatePage /> },
{ path: "settings/system-performance", element: <SystemPerformancePage /> },
{ path: "settings/libtv", element: <Navigate to="/admin/settings/third-party" replace /> },
],
},
],
},
{ path: "*", element: fullScreenDeferred(<NotFound />) },
]);