"use client"; import { use, useState } from "react"; import Link from "next/link"; import { useRouter } from "next/navigation"; import { useQuery } from "@tanstack/react-query"; import { Button, Chip, Modal, Spinner } from "@heroui/react"; import { ArrowLeft, ArrowRotateRight, TrashBin } from "@gravity-ui/icons"; import { APIError, api } from "@/lib/api"; import { useSession } from "@/lib/auth-client"; import dayjs from "@/lib/dayjs"; function formatDuration(start: string, stop: string | null): string { if (!stop) return "进行中"; const min = dayjs(stop).diff(dayjs(start), "minute"); if (min < 60) return `${min} 分钟`; const h = Math.floor(min / 60); const m = min % 60; return `${h}h ${m}m`; } function formatDateTime(iso: string | null | undefined): string { if (!iso) return "—"; return dayjs(iso).format("YYYY/M/D HH:mm:ss"); } function formatEnergy(wh: number | null | undefined): string { if (wh == null) return "—"; return `${(wh / 1000).toFixed(3)} kWh`; } function formatAmount(fen: number | null | undefined): string { if (fen == null) return "—"; return `¥${(fen / 100).toFixed(2)}`; } export default function TransactionDetailPage({ params }: { params: Promise<{ id: string }> }) { const { id } = use(params); const router = useRouter(); const txId = Number(id); const isValidId = Number.isInteger(txId) && txId > 0; const [stopping, setStopping] = useState(false); const [deleting, setDeleting] = useState(false); const { data: sessionData } = useSession(); const isAdmin = sessionData?.user?.role === "admin"; const { data: tx, isPending, isFetching, isError, error, refetch, } = useQuery({ queryKey: ["transaction", txId], queryFn: () => api.transactions.get(txId), enabled: isValidId, refetchInterval: 3_000, retry: false, }); const handleStop = async () => { if (!tx) return; setStopping(true); try { await api.transactions.stop(tx.id); await refetch(); } finally { setStopping(false); } }; const handleDelete = async () => { if (!tx) return; setDeleting(true); try { await api.transactions.delete(tx.id); router.push("/dashboard/transactions"); } finally { setDeleting(false); } }; if (!isValidId) { return (
充电记录

无效的交易编号。

); } if (isPending) { return (
); } if (isError || !tx) { const notFound = error instanceof APIError && error.status === 404; return (
充电记录

{notFound ? "交易记录不存在。" : "加载交易记录失败。"}

); } const energyWh = tx.energyWh ?? tx.liveEnergyWh; const amountFen = tx.chargeAmount ?? tx.estimatedCost; const isEstimatedEnergy = tx.energyWh == null && tx.liveEnergyWh != null; const isEstimatedAmount = tx.chargeAmount == null && tx.estimatedCost != null; return (
充电记录

充电订单#{tx.id}

{tx.stopTimestamp ? ( 已完成 ) : ( 进行中 )} {isEstimatedAmount && ( 费用预估 )}

开始于 {formatDateTime(tx.startTimestamp)} · {tx.stopTimestamp ? "时长 " : ""} {formatDuration(tx.startTimestamp, tx.stopTimestamp)}

{!tx.stopTimestamp && ( 确认中止充电

将远程中止充电交易{" "} #{tx.id}

)} {isAdmin && ( 确认删除记录

将永久删除交易 #{tx.id}

)}

充电量

{formatEnergy(energyWh)}

{isEstimatedEnergy && ( 预估 )}

总费用

{formatAmount(amountFen)}

{isEstimatedAmount && ( 预估 )}

状态

{tx.stopTimestamp ? "已完成" : "进行中"}

停止原因

{tx.stopReason ?? "—"}

交易信息

交易编号
#{tx.id}
储值卡
{tx.idTag}
桩编号
{tx.chargePointIdentifier ?? "—"}
连接器
{tx.connectorNumber ?? "—"}
开始时间
{formatDateTime(tx.startTimestamp)}
结束时间
{formatDateTime(tx.stopTimestamp)}
持续时长
{formatDuration(tx.startTimestamp, tx.stopTimestamp)}

计量与费用

起始表计
{tx.startMeterValue != null ? `${tx.startMeterValue} Wh` : "—"}
结束表计
{tx.stopMeterValue != null ? `${tx.stopMeterValue} Wh` : "—"}
消耗电量
{formatEnergy(energyWh)} {isEstimatedEnergy && ( 预估 )}
电费
{formatAmount(tx.electricityFee)}
服务费
{formatAmount(tx.serviceFee)}
总费用
{formatAmount(amountFen)} {isEstimatedAmount && ( 预估 )}
); }