feat: integrate React Query for data fetching and state management across dashboard components

This commit is contained in:
2026-03-11 00:15:07 +08:00
parent 984274bfb7
commit eac81d2fab
9 changed files with 121 additions and 154 deletions

View File

@@ -1,6 +1,6 @@
"use client";
import { useCallback, useEffect, useState } from "react";
import { useQuery } from "@tanstack/react-query";
import { Card, Spinner } from "@heroui/react";
import {
Thunderbolt,
@@ -191,37 +191,21 @@ export default function DashboardPage() {
const { data: sessionData, isPending } = useSession();
const isAdmin = sessionData?.user?.role === "admin";
const [adminStats, setAdminStats] = useState<Stats | null>(null);
const [userStats, setUserStats] = useState<UserStats | null>(null);
const [recentTxns, setRecentTxns] = useState<Transaction[]>([]);
const [chargePoints, setChargePoints] = useState<ChargePoint[]>([]);
const [loading, setLoading] = useState(false);
const load = useCallback(async () => {
if (isPending) return;
setLoading(true);
try {
const [statsData, txnsData, cpsData] = await Promise.all([
const { data, isPending: queryPending } = useQuery({
queryKey: ["dashboard", isAdmin],
queryFn: async () => {
const [statsRes, txRes, cpsData] = await Promise.all([
api.stats.get(),
api.transactions.list({ limit: 6 }),
isAdmin ? api.chargePoints.list() : Promise.resolve(null),
isAdmin ? api.chargePoints.list() : Promise.resolve([] as ChargePoint[]),
]);
if ("totalChargePoints" in statsData) {
setAdminStats(statsData as Stats);
} else {
setUserStats(statsData as UserStats);
}
setRecentTxns(txnsData.data);
if (cpsData) setChargePoints(cpsData);
} catch {}
finally {
setLoading(false);
}
}, [isPending, isAdmin]);
return { stats: statsRes, txns: txRes.data, cps: cpsData };
},
refetchInterval: 3_000,
enabled: !isPending,
});
useEffect(() => { void load(); }, [load]);
if (isPending || loading) {
if (isPending || queryPending) {
return (
<div className="space-y-6">
<div>
@@ -238,7 +222,7 @@ export default function DashboardPage() {
// ── Admin view ────────────────────────────────────────────────────────────
if (isAdmin) {
const s = adminStats;
const s = data?.stats as Stats | undefined;
const todayKwh = s ? (s.todayEnergyWh / 1000).toFixed(1) : "—";
const todayRevenue = s ? `¥${(s.todayRevenue / 100).toFixed(2)}` : "—";
const offlineCount = (s?.totalChargePoints ?? 0) - (s?.onlineChargePoints ?? 0);
@@ -327,12 +311,12 @@ export default function DashboardPage() {
<div className="grid grid-cols-1 gap-4 lg:grid-cols-5">
<div className="lg:col-span-2">
<Panel title="充电桩状态">
<ChargePointStatus cps={chargePoints} />
<ChargePointStatus cps={data?.cps ?? []} />
</Panel>
</div>
<div className="lg:col-span-3">
<Panel title="最近充电会话">
<RecentTransactions txns={recentTxns} />
<RecentTransactions txns={data?.txns ?? []} />
</Panel>
</div>
</div>
@@ -342,7 +326,7 @@ export default function DashboardPage() {
// ── User view ─────────────────────────────────────────────────────────────
const s = userStats;
const s = data?.stats as UserStats | undefined;
const totalYuan = s ? (s.totalBalance / 100).toFixed(2) : "—";
const todayKwh = s ? (s.todayEnergyWh / 1000).toFixed(2) : "—";
@@ -394,7 +378,7 @@ export default function DashboardPage() {
</div>
<Panel title="最近充电记录">
<RecentTransactions txns={recentTxns} />
<RecentTransactions txns={data?.txns ?? []} />
</Panel>
</div>
);