feat: polish BI dashboards and bump version
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful

This commit is contained in:
lingniu
2026-06-27 21:59:33 +08:00
parent 5377d2c225
commit b0caa5afcb
33 changed files with 2363 additions and 483 deletions

View File

@@ -1,18 +1,20 @@
import { useEffect, useMemo, useState } from "react";
import { lazy, Suspense, useEffect, useMemo, useState } from "react";
import { Truck, Route, Activity, Fuel, BatteryCharging, Receipt } from "lucide-react";
import { Shell, type ModuleConfig } from "./components/Shell";
import AssetsModule from "./modules/assets/AssetsModule";
import MileageModule from "./modules/mileage/MileageModule";
import SchedulingModule from "./modules/scheduling/SchedulingModule";
import HydrogenModule from "./modules/energy/HydrogenModule";
import ElectricModule from "./modules/energy/ElectricModule";
import EtcModule from "./modules/energy/EtcModule";
import EleImportPage from "./modules/ele/EleImportPage";
import FeedbackAdminPage from "./modules/admin/FeedbackAdminPage";
import AuthProvider from "./auth/AuthProvider";
import { useAuth } from "./auth/useAuth";
import UnauthorizedPage from "./auth/UnauthorizedPage";
import { canAccessScheduling, canAccessEnergy } from "./shared/auth/roles";
import { LoadingState, SkeletonBlock, SurfaceCard } from "./components/ui/surface";
const AssetsModule = lazy(() => import("./modules/assets/AssetsModule"));
const MileageModule = lazy(() => import("./modules/mileage/MileageModule"));
const SchedulingModule = lazy(() => import("./modules/scheduling/SchedulingModule"));
const HydrogenModule = lazy(() => import("./modules/energy/HydrogenModule"));
const ElectricModule = lazy(() => import("./modules/energy/ElectricModule"));
const EtcModule = lazy(() => import("./modules/energy/EtcModule"));
const EleImportPage = lazy(() => import("./modules/ele/EleImportPage"));
const FeedbackAdminPage = lazy(() => import("./modules/admin/FeedbackAdminPage"));
const ASSETS_MODULE: ModuleConfig = {
id: "assets",
@@ -143,10 +145,21 @@ function AuthGate() {
if (isLoading) {
return (
<div className="min-h-screen bg-[#F8F9FB] flex items-center justify-center">
<div className="text-center">
<div className="w-8 h-8 border-2 border-blue-600 border-t-transparent rounded-full animate-spin mx-auto mb-3"></div>
<p className="text-xs text-slate-400 font-bold">...</p>
<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>
);
@@ -157,8 +170,20 @@ function AuthGate() {
}
// 隐藏后端管理页:通过路径或 hash 直接访问,主导航不出现
if (routeKey === "ele/import") return <EleImportPage />;
if (routeKey === "admin/feedback") return <FeedbackAdminPage />;
if (routeKey === "ele/import") {
return (
<Suspense fallback={<LoadingState label="正在加载导入工作台" />}>
<EleImportPage />
</Suspense>
);
}
if (routeKey === "admin/feedback") {
return (
<Suspense fallback={<LoadingState label="正在加载反馈后台" />}>
<FeedbackAdminPage />
</Suspense>
);
}
// /energy 整组按能源权限控制
if (pathSet === "energy" && !canAccessEnergy(user?.roles)) {