feat: RBAC controlling
This commit is contained in:
@@ -1,8 +1,10 @@
|
||||
import { Card } from "@heroui/react";
|
||||
import { Thunderbolt, PlugConnection, CreditCard, ChartColumn } from "@gravity-ui/icons";
|
||||
import { api } from "@/lib/api";
|
||||
"use client";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
import { useEffect, useState } from "react";
|
||||
import { Card } from "@heroui/react";
|
||||
import { Thunderbolt, PlugConnection, CreditCard, ChartColumn, TagDollar } from "@gravity-ui/icons";
|
||||
import { useSession } from "@/lib/auth-client";
|
||||
import { api, type Stats, type UserStats } from "@/lib/api";
|
||||
|
||||
type CardColor = "accent" | "success" | "warning" | "default";
|
||||
|
||||
@@ -55,42 +57,134 @@ function StatCard({
|
||||
);
|
||||
}
|
||||
|
||||
export default async function DashboardPage() {
|
||||
const stats = await api.stats.get().catch(() => null);
|
||||
export default function DashboardPage() {
|
||||
const { data: sessionData, isPending } = useSession();
|
||||
const isAdmin = sessionData?.user?.role === "admin";
|
||||
|
||||
const todayKwh = stats ? (stats.todayEnergyWh / 1000).toFixed(1) : "—";
|
||||
const offlineCount = (stats?.totalChargePoints ?? 0) - (stats?.onlineChargePoints ?? 0);
|
||||
const [adminStats, setAdminStats] = useState<Stats | null>(null);
|
||||
const [userStats, setUserStats] = useState<UserStats | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (isPending) return;
|
||||
api.stats
|
||||
.get()
|
||||
.then((data) => {
|
||||
if ("todayEnergyWh" in data) {
|
||||
setAdminStats(data);
|
||||
return;
|
||||
}
|
||||
setUserStats(data);
|
||||
})
|
||||
.catch(() => {});
|
||||
}, [isPending, isAdmin]);
|
||||
|
||||
if (isPending) {
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<div>
|
||||
<h1 className="text-xl font-semibold text-foreground">概览</h1>
|
||||
<p className="mt-0.5 text-sm text-muted">加载中…</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (isAdmin) {
|
||||
const stats = adminStats;
|
||||
const todayKwh = stats ? (stats.todayEnergyWh / 1000).toFixed(1) : "—";
|
||||
const offlineCount = (stats?.totalChargePoints ?? 0) - (stats?.onlineChargePoints ?? 0);
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<div>
|
||||
<h1 className="text-xl font-semibold text-foreground">概览</h1>
|
||||
<p className="mt-0.5 text-sm text-muted">实时运营状态</p>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2 xl:grid-cols-5">
|
||||
<StatCard
|
||||
title="充电桩总数"
|
||||
value={stats?.totalChargePoints ?? "—"}
|
||||
icon={PlugConnection}
|
||||
color="accent"
|
||||
footer={
|
||||
<>
|
||||
<StatusDot color="success" />
|
||||
<span className="font-medium text-success">
|
||||
{stats?.onlineChargePoints ?? 0} 在线
|
||||
</span>
|
||||
<span className="text-border">·</span>
|
||||
<span>{offlineCount} 离线</span>
|
||||
</>
|
||||
}
|
||||
/>
|
||||
<StatCard
|
||||
title="在线充电桩"
|
||||
value={stats?.onlineChargePoints ?? "—"}
|
||||
icon={PlugConnection}
|
||||
color="success"
|
||||
footer={<span>最近 2 分钟有心跳</span>}
|
||||
/>
|
||||
<StatCard
|
||||
title="进行中充电"
|
||||
value={stats?.activeTransactions ?? "—"}
|
||||
icon={Thunderbolt}
|
||||
color={stats?.activeTransactions ? "warning" : "default"}
|
||||
footer={
|
||||
<>
|
||||
<StatusDot color={stats?.activeTransactions ? "success" : "muted"} />
|
||||
<span className={stats?.activeTransactions ? "font-medium text-success" : ""}>
|
||||
{stats?.activeTransactions ? "活跃中" : "当前空闲"}
|
||||
</span>
|
||||
</>
|
||||
}
|
||||
/>
|
||||
<StatCard
|
||||
title="储值卡总数"
|
||||
value={stats?.totalIdTags ?? "—"}
|
||||
icon={CreditCard}
|
||||
color="default"
|
||||
footer={<span>已注册卡片总量</span>}
|
||||
/>
|
||||
<StatCard
|
||||
title="今日充电量"
|
||||
value={`${todayKwh} kWh`}
|
||||
icon={ChartColumn}
|
||||
color="accent"
|
||||
footer={<span>当日 00:00 起累计</span>}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// User view
|
||||
const stats = userStats;
|
||||
const totalYuan = stats ? (stats.totalBalance / 100).toFixed(2) : "—";
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<div>
|
||||
<h1 className="text-xl font-semibold text-foreground">概览</h1>
|
||||
<p className="mt-0.5 text-sm text-muted">实时运营状态</p>
|
||||
<p className="mt-0.5 text-sm text-muted">
|
||||
{sessionData?.user?.name ?? sessionData?.user?.email} 的账户概览
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2 xl:grid-cols-5">
|
||||
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2 xl:grid-cols-4">
|
||||
<StatCard
|
||||
title="充电桩总数"
|
||||
value={stats?.totalChargePoints ?? "—"}
|
||||
icon={PlugConnection}
|
||||
title="我的储值卡"
|
||||
value={stats?.totalIdTags ?? "—"}
|
||||
icon={CreditCard}
|
||||
color="accent"
|
||||
footer={
|
||||
<>
|
||||
<StatusDot color="success" />
|
||||
<span className="font-medium text-success">
|
||||
{stats?.onlineChargePoints ?? 0} 在线
|
||||
</span>
|
||||
<span className="text-border">·</span>
|
||||
<span>{offlineCount} 离线</span>
|
||||
</>
|
||||
}
|
||||
footer={<span>已绑定的储值卡数量</span>}
|
||||
/>
|
||||
<StatCard
|
||||
title="在线充电桩"
|
||||
value={stats?.onlineChargePoints ?? "—"}
|
||||
icon={PlugConnection}
|
||||
title="账户总余额"
|
||||
value={`¥${totalYuan}`}
|
||||
icon={TagDollar}
|
||||
color="success"
|
||||
footer={<span>最近 2 分钟有心跳</span>}
|
||||
footer={<span>所有储值卡余额合计</span>}
|
||||
/>
|
||||
<StatCard
|
||||
title="进行中充电"
|
||||
@@ -101,24 +195,17 @@ export default async function DashboardPage() {
|
||||
<>
|
||||
<StatusDot color={stats?.activeTransactions ? "success" : "muted"} />
|
||||
<span className={stats?.activeTransactions ? "font-medium text-success" : ""}>
|
||||
{stats?.activeTransactions ? "活跃中" : "当前空闲"}
|
||||
{stats?.activeTransactions ? "充电中" : "当前空闲"}
|
||||
</span>
|
||||
</>
|
||||
}
|
||||
/>
|
||||
<StatCard
|
||||
title="储值卡总数"
|
||||
value={stats?.totalIdTags ?? "—"}
|
||||
icon={CreditCard}
|
||||
color="default"
|
||||
footer={<span>已注册卡片总量</span>}
|
||||
/>
|
||||
<StatCard
|
||||
title="今日充电量"
|
||||
value={`${todayKwh} kWh`}
|
||||
title="累计充电次数"
|
||||
value={stats?.totalTransactions ?? "—"}
|
||||
icon={ChartColumn}
|
||||
color="accent"
|
||||
footer={<span>当日 00:00 起累计</span>}
|
||||
color="default"
|
||||
footer={<span>历史总交易笔数</span>}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user