feat(api): add stats chart endpoint for admin access with time series data
feat(dayjs): integrate dayjs for date handling and formatting across the application refactor(routes): update date handling in id-tags, transactions, users, and dashboard routes to use dayjs style(globals): improve CSS variable definitions for better readability and consistency deps: add dayjs as a dependency for date manipulation
This commit is contained in:
@@ -6,13 +6,13 @@ import { Button, Chip, Modal, Pagination, Spinner, Table } from "@heroui/react";
|
||||
import { TrashBin, ArrowRotateRight } from "@gravity-ui/icons";
|
||||
import { api } from "@/lib/api";
|
||||
import { useSession } from "@/lib/auth-client";
|
||||
import dayjs from "@/lib/dayjs";
|
||||
|
||||
const LIMIT = 15;
|
||||
|
||||
function formatDuration(start: string, stop: string | null): string {
|
||||
if (!stop) return "进行中";
|
||||
const ms = new Date(stop).getTime() - new Date(start).getTime();
|
||||
const min = Math.floor(ms / 60000);
|
||||
const min = dayjs(stop).diff(dayjs(start), "minute");
|
||||
if (min < 60) return `${min} 分钟`;
|
||||
const h = Math.floor(min / 60);
|
||||
const m = min % 60;
|
||||
@@ -78,23 +78,32 @@ export default function TransactionsPage() {
|
||||
<p className="mt-0.5 text-sm text-muted">共 {data?.total ?? "—"} 条</p>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<Button isIconOnly size="sm" variant="ghost" isDisabled={refreshing} onPress={() => refetch()} aria-label="刷新">
|
||||
<Button
|
||||
isIconOnly
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
isDisabled={refreshing}
|
||||
onPress={() => refetch()}
|
||||
aria-label="刷新"
|
||||
>
|
||||
<ArrowRotateRight className={`size-4 ${refreshing ? "animate-spin" : ""}`} />
|
||||
</Button>
|
||||
<div className="flex gap-1.5 rounded-xl bg-surface-secondary p-1">
|
||||
{(["all", "active", "completed"] as const).map((s) => (
|
||||
<button
|
||||
key={s}
|
||||
onClick={() => handleStatusChange(s)}
|
||||
className={`rounded-lg px-3 py-1 text-sm font-medium transition-colors ${
|
||||
status === s
|
||||
? "bg-surface text-foreground shadow-sm"
|
||||
: "text-muted hover:text-foreground"
|
||||
}`}
|
||||
>
|
||||
{s === "all" ? "全部" : s === "active" ? "进行中" : "已完成"}
|
||||
</button>
|
||||
))} </div> </div>
|
||||
{(["all", "active", "completed"] as const).map((s) => (
|
||||
<button
|
||||
key={s}
|
||||
onClick={() => handleStatusChange(s)}
|
||||
className={`rounded-lg px-3 py-1 text-sm font-medium transition-colors ${
|
||||
status === s
|
||||
? "bg-surface text-foreground shadow-sm"
|
||||
: "text-muted hover:text-foreground"
|
||||
}`}
|
||||
>
|
||||
{s === "all" ? "全部" : s === "active" ? "进行中" : "已完成"}
|
||||
</button>
|
||||
))}{" "}
|
||||
</div>{" "}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Table>
|
||||
@@ -138,7 +147,7 @@ export default function TransactionsPage() {
|
||||
)}
|
||||
</Table.Cell>
|
||||
<Table.Cell className="whitespace-nowrap text-sm">
|
||||
{new Date(tx.startTimestamp).toLocaleString("zh-CN")}
|
||||
{dayjs(tx.startTimestamp).format("YYYY/M/D HH:mm:ss")}
|
||||
</Table.Cell>
|
||||
<Table.Cell className="text-sm">
|
||||
{formatDuration(tx.startTimestamp, tx.stopTimestamp)}
|
||||
|
||||
Reference in New Issue
Block a user