From 4d0c429d5f37c631c20a90e3af6a4232e25b8424 Mon Sep 17 00:00:00 2001 From: Timothy Yin Date: Wed, 11 Mar 2026 00:18:12 +0800 Subject: [PATCH] chore: format code --- .../app/dashboard/charge-points/[id]/page.tsx | 195 +++++++++--------- apps/web/app/dashboard/id-tags/page.tsx | 71 ++++--- apps/web/app/dashboard/layout.tsx | 12 +- apps/web/app/dashboard/page.tsx | 13 +- apps/web/app/dashboard/settings/page.tsx | 36 +++- apps/web/app/dashboard/transactions/page.tsx | 103 ++++----- apps/web/app/layout.tsx | 7 +- apps/web/app/login/page.tsx | 2 +- apps/web/app/page.tsx | 4 +- apps/web/components/sidebar-footer.tsx | 24 +-- apps/web/components/sidebar.tsx | 140 +++++++------ apps/web/lib/api.ts | 22 +- 12 files changed, 334 insertions(+), 295 deletions(-) diff --git a/apps/web/app/dashboard/charge-points/[id]/page.tsx b/apps/web/app/dashboard/charge-points/[id]/page.tsx index 23d2d79..ca66225 100644 --- a/apps/web/app/dashboard/charge-points/[id]/page.tsx +++ b/apps/web/app/dashboard/charge-points/[id]/page.tsx @@ -17,7 +17,7 @@ import { TextField, } from "@heroui/react"; import { ArrowLeft, Pencil, PlugConnection } from "@gravity-ui/icons"; -import { api, type ChargePointDetail, type PaginatedTransactions } from "@/lib/api"; +import { api } from "@/lib/api"; import { useSession } from "@/lib/auth-client"; // ── Status maps ──────────────────────────────────────────────────────────── @@ -116,8 +116,7 @@ export default function ChargePointDetailPage({ params }: { params: Promise<{ id const txQuery = useQuery({ queryKey: ["chargePointTransactions", id, txPage], - queryFn: () => - api.transactions.list({ page: txPage, limit: TX_LIMIT, chargePointId: id }), + queryFn: () => api.transactions.list({ page: txPage, limit: TX_LIMIT, chargePointId: id }), refetchInterval: 3_000, }); @@ -240,104 +239,104 @@ export default function ChargePointDetailPage({ params }: { params: Promise<{ id
{/* Device info — admin only */} {isAdmin && ( -
-

设备信息

-
- {[ - { label: "品牌", value: cp.chargePointVendor }, - { label: "型号", value: cp.chargePointModel }, - { label: "序列号", value: cp.chargePointSerialNumber }, - { label: "固件版本", value: cp.firmwareVersion }, - { label: "电表型号", value: cp.meterType }, - { label: "电表序列号", value: cp.meterSerialNumber }, - { label: "ICCID", value: cp.iccid }, - { label: "IMSI", value: cp.imsi }, - ].map(({ label, value }) => ( -
-
{label}
-
- {value ?? } -
-
- ))} -
-
+
+

设备信息

+
+ {[ + { label: "品牌", value: cp.chargePointVendor }, + { label: "型号", value: cp.chargePointModel }, + { label: "序列号", value: cp.chargePointSerialNumber }, + { label: "固件版本", value: cp.firmwareVersion }, + { label: "电表型号", value: cp.meterType }, + { label: "电表序列号", value: cp.meterSerialNumber }, + { label: "ICCID", value: cp.iccid }, + { label: "IMSI", value: cp.imsi }, + ].map(({ label, value }) => ( +
+
{label}
+
+ {value ?? } +
+
+ ))} +
+
)} {/* Operation info — admin only */} {isAdmin && ( -
-

运行配置

-
-
-
注册状态
-
- - {cp.registrationStatus} - -
-
-
-
电价
-
- {cp.feePerKwh > 0 ? ( - - {cp.feePerKwh} 分/kWh - - (¥{(cp.feePerKwh / 100).toFixed(2)}/kWh) +
+

运行配置

+
+
+
注册状态
+
+ + {cp.registrationStatus} + +
+
+
+
电价
+
+ {cp.feePerKwh > 0 ? ( + + {cp.feePerKwh} 分/kWh + + (¥{(cp.feePerKwh / 100).toFixed(2)}/kWh) + - - ) : ( - "免费" - )} -
-
-
-
心跳间隔
-
- {cp.heartbeatInterval != null ? ( - `${cp.heartbeatInterval} 秒` - ) : ( - - )} -
-
-
-
最后心跳
-
- {cp.lastHeartbeatAt ? ( - - {relativeTime(cp.lastHeartbeatAt)} - - ) : ( - - )} -
-
-
-
最后启动通知
-
- {cp.lastBootNotificationAt ? ( - - {relativeTime(cp.lastBootNotificationAt)} - - ) : ( - - )} -
-
-
-
注册时间
-
- {new Date(cp.createdAt).toLocaleDateString("zh-CN")} -
-
-
-
+ ) : ( + "免费" + )} +
+
+
+
心跳间隔
+
+ {cp.heartbeatInterval != null ? ( + `${cp.heartbeatInterval} 秒` + ) : ( + + )} +
+
+
+
最后心跳
+
+ {cp.lastHeartbeatAt ? ( + + {relativeTime(cp.lastHeartbeatAt)} + + ) : ( + + )} +
+
+
+
最后启动通知
+
+ {cp.lastBootNotificationAt ? ( + + {relativeTime(cp.lastBootNotificationAt)} + + ) : ( + + )} +
+
+
+
注册时间
+
+ {new Date(cp.createdAt).toLocaleDateString("zh-CN")} +
+
+
+
)} {/* Fee info — user only */} @@ -362,7 +361,9 @@ export default function ChargePointDetailPage({ params }: { params: Promise<{ id
充电桥状态
- + {isOnline ? "在线" : "离线"}
diff --git a/apps/web/app/dashboard/id-tags/page.tsx b/apps/web/app/dashboard/id-tags/page.tsx index 2f2fe0e..6e7dcf5 100644 --- a/apps/web/app/dashboard/id-tags/page.tsx +++ b/apps/web/app/dashboard/id-tags/page.tsx @@ -337,7 +337,12 @@ export default function IdTagsPage() { const [deletingTag, setDeletingTag] = useState(null); const [claiming, setClaiming] = useState(false); - const { data: idTagsData, isPending: loading, isFetching: refreshing, refetch } = useQuery({ + const { + data: idTagsData, + isPending: loading, + isFetching: refreshing, + refetch, + } = useQuery({ queryKey: ["idTags"], queryFn: async () => { const [tagList, userList] = await Promise.all([ @@ -435,38 +440,38 @@ export default function IdTagsPage() { - - - - - - - 新增储值卡 - - - - - - - - - - - - + + + + + + + 新增储值卡 + + + + + + + + + + + +
) : ( - - - - - - 确认删除记录 - - -

- 将永久删除充电记录{" "} - - #{tx.id} - - (储值卡:{tx.idTag})。 - {!tx.stopTimestamp && "该记录仍进行中,删除同时将重置接口状态。"} -

-
- - - - -
-
-
- + + + + + + + + 确认删除记录 + + +

+ 将永久删除充电记录{" "} + + #{tx.id} + + (储值卡:{tx.idTag})。 + {!tx.stopTimestamp && + "该记录仍进行中,删除同时将重置接口状态。"} +

+
+ + + + +
+
+
+
)} diff --git a/apps/web/app/layout.tsx b/apps/web/app/layout.tsx index 7c82e51..8b484cc 100644 --- a/apps/web/app/layout.tsx +++ b/apps/web/app/layout.tsx @@ -5,12 +5,12 @@ import "./globals.css"; const fontSaira = Saira({ variable: "--font-saira", subsets: ["latin"], -}) +}); const fontNotoSans = Noto_Sans({ variable: "--font-noto-sans", subsets: ["latin"], -}) +}); const fontMono = Geist_Mono({ variable: "--font-geist-mono", @@ -19,7 +19,8 @@ const fontMono = Geist_Mono({ export const metadata: Metadata = { title: "Helios EVCS", - description: "A modern EV charging station management system built with Next.js, Drizzle ORM, and OCPP.", + description: + "A modern EV charging station management system built with Next.js, Drizzle ORM, and OCPP.", }; export default function RootLayout({ diff --git a/apps/web/app/login/page.tsx b/apps/web/app/login/page.tsx index 81e6e0e..1d58a6a 100644 --- a/apps/web/app/login/page.tsx +++ b/apps/web/app/login/page.tsx @@ -141,7 +141,7 @@ export default function LoginPage() { -

OCPP 1.6-J Protocol • v0.1.0

+

Helios EVCS

); } diff --git a/apps/web/app/page.tsx b/apps/web/app/page.tsx index 28c5ca1..a74cb27 100644 --- a/apps/web/app/page.tsx +++ b/apps/web/app/page.tsx @@ -1,5 +1,5 @@ -import { redirect } from 'next/navigation' +import { redirect } from "next/navigation"; export default function Home() { - redirect('/dashboard') + redirect("/dashboard"); } diff --git a/apps/web/components/sidebar-footer.tsx b/apps/web/components/sidebar-footer.tsx index 0cffc33..2cc38bb 100644 --- a/apps/web/components/sidebar-footer.tsx +++ b/apps/web/components/sidebar-footer.tsx @@ -1,18 +1,18 @@ -'use client' +"use client"; -import { useRouter } from 'next/navigation' -import { ArrowRightFromSquare, PersonFill } from '@gravity-ui/icons' -import { signOut, useSession } from '@/lib/auth-client' +import { useRouter } from "next/navigation"; +import { ArrowRightFromSquare, PersonFill } from "@gravity-ui/icons"; +import { signOut, useSession } from "@/lib/auth-client"; export default function SidebarFooter() { - const router = useRouter() - const { data: session } = useSession() + const router = useRouter(); + const { data: session } = useSession(); const handleSignOut = async () => { - await signOut({ fetchOptions: { credentials: 'include' } }) - router.push('/login') - router.refresh() - } + await signOut({ fetchOptions: { credentials: "include" } }); + router.push("/login"); + router.refresh(); + }; return (
@@ -27,7 +27,7 @@ export default function SidebarFooter() { {session.user.name || session.user.email}

- {session.user.role ?? 'user'} + {session.user.role ?? "user"}

@@ -44,5 +44,5 @@ export default function SidebarFooter() {

Helios EVCS

- ) + ); } diff --git a/apps/web/components/sidebar.tsx b/apps/web/components/sidebar.tsx index 5ee75c7..55e9bdc 100644 --- a/apps/web/components/sidebar.tsx +++ b/apps/web/components/sidebar.tsx @@ -1,25 +1,40 @@ -'use client' +"use client"; -import Link from 'next/link' -import { usePathname } from 'next/navigation' -import { useState } from 'react' -import { CreditCard, Gear, ListCheck, Person, PlugConnection, Thunderbolt, Xmark, Bars } from '@gravity-ui/icons' -import SidebarFooter from '@/components/sidebar-footer' -import { useSession } from '@/lib/auth-client' +import Link from "next/link"; +import { usePathname } from "next/navigation"; +import { useState } from "react"; +import { + CreditCard, + Gear, + ListCheck, + Person, + PlugConnection, + Thunderbolt, + Xmark, + Bars, +} from "@gravity-ui/icons"; +import SidebarFooter from "@/components/sidebar-footer"; +import { useSession } from "@/lib/auth-client"; const navItems = [ - { href: '/dashboard', label: '概览', icon: Thunderbolt, exact: true, adminOnly: false }, - { href: '/dashboard/charge-points', label: '充电桩', icon: PlugConnection, adminOnly: false }, - { href: '/dashboard/transactions', label: '充电记录', icon: ListCheck, adminOnly: false }, - { href: '/dashboard/id-tags', label: '储值卡', icon: CreditCard, adminOnly: false }, - { href: '/dashboard/users', label: '用户管理', icon: Person, adminOnly: true }, -] + { href: "/dashboard", label: "概览", icon: Thunderbolt, exact: true, adminOnly: false }, + { href: "/dashboard/charge-points", label: "充电桩", icon: PlugConnection, adminOnly: false }, + { href: "/dashboard/transactions", label: "充电记录", icon: ListCheck, adminOnly: false }, + { href: "/dashboard/id-tags", label: "储值卡", icon: CreditCard, adminOnly: false }, + { href: "/dashboard/users", label: "用户管理", icon: Person, adminOnly: true }, +]; -const settingsItems = [ - { href: '/dashboard/settings', label: '账号设置', icon: Gear }, -] +const settingsItems = [{ href: "/dashboard/settings", label: "账号设置", icon: Gear }]; -function NavContent({ pathname, isAdmin, onNavigate }: { pathname: string; isAdmin: boolean; onNavigate?: () => void }) { +function NavContent({ + pathname, + isAdmin, + onNavigate, +}: { + pathname: string; + isAdmin: boolean; + onNavigate?: () => void; +}) { return ( <> {/* Logo */} @@ -37,70 +52,68 @@ function NavContent({ pathname, isAdmin, onNavigate }: { pathname: string; isAdm

管理

- {navItems.filter((item) => !item.adminOnly || isAdmin).map((item) => { - const isActive = item.exact - ? pathname === item.href - : pathname === item.href || pathname.startsWith(item.href + '/') - const Icon = item.icon - return ( - - - {item.label} - {isActive && ( - - )} - - ) - })} + {navItems + .filter((item) => !item.adminOnly || isAdmin) + .map((item) => { + const isActive = item.exact + ? pathname === item.href + : pathname === item.href || pathname.startsWith(item.href + "/"); + const Icon = item.icon; + return ( + + + {item.label} + {isActive && } + + ); + })}

设置

{settingsItems.map((item) => { - const isActive = pathname === item.href || pathname.startsWith(item.href + '/') - const Icon = item.icon + const isActive = pathname === item.href || pathname.startsWith(item.href + "/"); + const Icon = item.icon; return ( {item.label} - {isActive && ( - - )} + {isActive && } - ) + ); })} {/* Footer */} - ) + ); } export default function Sidebar() { - const pathname = usePathname() - const [open, setOpen] = useState(false) - const { data: sessionData } = useSession() - const isAdmin = sessionData?.user?.role === "admin" + const pathname = usePathname(); + const [open, setOpen] = useState(false); + const { data: sessionData } = useSession(); + const isAdmin = sessionData?.user?.role === "admin"; return ( <> @@ -124,18 +137,15 @@ export default function Sidebar() { {/* Mobile drawer overlay */} {open && ( -
setOpen(false)} - /> +
setOpen(false)} /> )} {/* Mobile drawer */} - ) + ); } diff --git a/apps/web/lib/api.ts b/apps/web/lib/api.ts index bff39ba..59254ec 100644 --- a/apps/web/lib/api.ts +++ b/apps/web/lib/api.ts @@ -156,12 +156,15 @@ export const api = { method: "POST", body: JSON.stringify(data), }), - update: (id: string, data: { - feePerKwh?: number; - registrationStatus?: "Accepted" | "Pending" | "Rejected"; - chargePointVendor?: string; - chargePointModel?: string; - }) => + update: ( + id: string, + data: { + feePerKwh?: number; + registrationStatus?: "Accepted" | "Pending" | "Rejected"; + chargePointVendor?: string; + chargePointModel?: string; + }, + ) => apiFetch(`/api/charge-points/${id}`, { method: "PATCH", body: JSON.stringify(data), @@ -170,7 +173,12 @@ export const api = { apiFetch<{ success: true }>(`/api/charge-points/${id}`, { method: "DELETE" }), }, transactions: { - list: (params?: { page?: number; limit?: number; status?: "active" | "completed"; chargePointId?: string }) => { + list: (params?: { + page?: number; + limit?: number; + status?: "active" | "completed"; + chargePointId?: string; + }) => { const q = new URLSearchParams(); if (params?.page) q.set("page", String(params.page)); if (params?.limit) q.set("limit", String(params.limit));