src/vendor 语义是'第三方/参考',却装着线上氢能看板并反向 import
src/modules,依赖方向倒挂。本次把生产代码归位并建立氢能分层:
src/modules/energy/hydrogen/
index.tsx 导航入口(原 HydrogenModule.tsx)
api.ts types.ts HTTP 与 DTO
dev-mock-api.ts 仅 dev 的 vite 插件(仍由 vite.config.ts 引用)
model/ 纯逻辑(format / bearing-labels / daily-detail-format)
board/ 经营看板 UI(原 vendor energy-h2-bi-board)
station-daily/ 单站日报 UI(原 vendor energy-h2-station-daily)
drill/ 下钻弹层 UI(原 hydrogen-bi-v2 的 UI 部分)
common/ 工具与共享组件(原 vendor common + prototype-download)
fonts/ JetBrains Mono(原 vendor resources/design-system)
- UI 与 CSS 逐字节保留,仅移动位置与改写相对 import。
- 删除自挂载原型入口后遗留的 2 个 annotation-source.json。
- vite.config.ts 与 tsconfig 的路径/exclude 同步清理。
- independent-entry.test.ts 不再硬编码路径,改为断言'两个入口解析到同一文件'。
导入改写用一次性 codemod 完成(按旧位置解析、按新位置重写),
lint / test(131) / build 全绿,可达性分析仍为 0 未引用文件。
121 lines
4.1 KiB
TypeScript
121 lines
4.1 KiB
TypeScript
import { lazy, Suspense, useEffect, useMemo, useState } from "react";
|
|
import { Shell } from "./components/Shell";
|
|
import AuthProvider from "./auth/AuthProvider";
|
|
import { useAuth } from "./auth/useAuth";
|
|
import UnauthorizedPage from "./auth/UnauthorizedPage";
|
|
import PasswordLogin from "./auth/PasswordLogin";
|
|
import { canAccessEnergy } from "./shared/auth/roles";
|
|
import { LoadingState, SkeletonBlock, SurfaceCard } from "./components/ui/surface";
|
|
import { buildModules } from "./app/modules";
|
|
import {
|
|
normalizeBrowserPath,
|
|
readBrowserRoute,
|
|
} from "./app/routing";
|
|
|
|
const EleImportPage = lazy(() => import("./modules/ele/EleImportPage"));
|
|
const FeedbackAdminPage = lazy(() => import("./modules/admin/FeedbackAdminPage"));
|
|
const HydrogenPrototypeBoard = lazy(
|
|
() =>
|
|
import("./modules/energy/hydrogen/board/EnergyBiBoardApp").then(
|
|
({ EnergyBiBoardApp }) => ({ default: EnergyBiBoardApp }),
|
|
),
|
|
);
|
|
normalizeBrowserPath();
|
|
|
|
function AuthGate() {
|
|
const { isLoading, isAuthenticated, error, user, mode } = useAuth();
|
|
const [route, setRoute] = useState(readBrowserRoute);
|
|
const { routeKey, pathSet } = route;
|
|
|
|
// 监听 hashchange / popstate,让 a href="#/..." 跳转与浏览器前进后退能即时生效
|
|
useEffect(() => {
|
|
const update = () => {
|
|
setRoute(readBrowserRoute());
|
|
};
|
|
window.addEventListener("hashchange", update);
|
|
window.addEventListener("popstate", update);
|
|
return () => {
|
|
window.removeEventListener("hashchange", update);
|
|
window.removeEventListener("popstate", update);
|
|
};
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
document.title = pathSet === "energy" ? "羚牛氢能-能源BI" : "羚牛氢能-资产BI";
|
|
}, [pathSet]);
|
|
|
|
const modules = useMemo(
|
|
() => buildModules(pathSet, user?.roles),
|
|
[pathSet, user?.roles],
|
|
);
|
|
|
|
if (isLoading) {
|
|
return (
|
|
<div className="min-h-screen bg-[var(--app-bg)] p-4 text-slate-800 md:p-8">
|
|
<div className="mx-auto flex max-w-5xl flex-col gap-4">
|
|
<div className="rounded-2xl border border-white/70 bg-white/86 p-5 shadow-[0_18px_60px_rgba(15,23,42,0.08)] backdrop-blur-xl">
|
|
<div className="mb-3 text-[11px] font-black text-blue-600">LN BI ACCESS</div>
|
|
<div className="text-xl font-black text-slate-950">正在进入羚牛氢能 BI</div>
|
|
<div className="mt-2 text-xs font-bold text-slate-400">校验登录态、权限与本地开发环境配置</div>
|
|
</div>
|
|
<SurfaceCard className="p-4">
|
|
<div className="grid gap-3 md:grid-cols-4">
|
|
{[0, 1, 2, 3].map(item => <SkeletonBlock key={item} className="h-24" />)}
|
|
</div>
|
|
<div className="mt-4">
|
|
<LoadingState label="正在验证身份" />
|
|
</div>
|
|
</SurfaceCard>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
if (!isAuthenticated) {
|
|
if (mode === 'password') return <PasswordLogin />;
|
|
return <UnauthorizedPage message={error || undefined} />;
|
|
}
|
|
|
|
// 隐藏后端管理页:通过路径或 hash 直接访问,主导航不出现
|
|
if (routeKey === "ele/import") {
|
|
return (
|
|
<Suspense fallback={<LoadingState label="正在加载导入工作台" />}>
|
|
<EleImportPage />
|
|
</Suspense>
|
|
);
|
|
}
|
|
if (routeKey === "admin/feedback") {
|
|
return (
|
|
<Suspense fallback={<LoadingState label="正在加载反馈后台" />}>
|
|
<FeedbackAdminPage />
|
|
</Suspense>
|
|
);
|
|
}
|
|
if (routeKey === "energy/hydrogen-board") {
|
|
if (!canAccessEnergy(user?.roles)) {
|
|
return <UnauthorizedPage message="无能源管理模块访问权限" />;
|
|
}
|
|
return (
|
|
<Suspense fallback={<LoadingState label="正在加载氢能经营看板" />}>
|
|
<HydrogenPrototypeBoard />
|
|
</Suspense>
|
|
);
|
|
}
|
|
|
|
// /energy 整组按能源权限控制
|
|
if (pathSet === "energy" && !canAccessEnergy(user?.roles)) {
|
|
return <UnauthorizedPage message="无能源管理模块访问权限" />;
|
|
}
|
|
|
|
// key={pathSet} 让两套底栏切换时 Shell 内部 state 重置,避免残留旧 activeModule
|
|
return <Shell key={pathSet} modules={modules} />;
|
|
}
|
|
|
|
export default function App() {
|
|
return (
|
|
<AuthProvider>
|
|
<AuthGate />
|
|
</AuthProvider>
|
|
);
|
|
}
|