mirror of
https://github.com/woodchen-ink/nezha-dash-v1.git
synced 2025-07-18 17:41:56 +08:00
feat(note): endDate info
This commit is contained in:
parent
e780521b0b
commit
91677dfd90
@ -1,7 +1,12 @@
|
|||||||
import ServerFlag from "@/components/ServerFlag";
|
import ServerFlag from "@/components/ServerFlag";
|
||||||
import ServerUsageBar from "@/components/ServerUsageBar";
|
import ServerUsageBar from "@/components/ServerUsageBar";
|
||||||
|
|
||||||
import { cn, formatNezhaInfo } from "@/lib/utils";
|
import {
|
||||||
|
cn,
|
||||||
|
formatNezhaInfo,
|
||||||
|
parsePublicNote,
|
||||||
|
getDaysBetweenDates,
|
||||||
|
} from "@/lib/utils";
|
||||||
import { NezhaServer } from "@/types/nezha-api";
|
import { NezhaServer } from "@/types/nezha-api";
|
||||||
import { Card } from "./ui/card";
|
import { Card } from "./ui/card";
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
@ -29,10 +34,27 @@ export default function ServerCard({
|
|||||||
stg,
|
stg,
|
||||||
net_in_transfer,
|
net_in_transfer,
|
||||||
net_out_transfer,
|
net_out_transfer,
|
||||||
|
public_note,
|
||||||
} = formatNezhaInfo(now, serverInfo);
|
} = formatNezhaInfo(now, serverInfo);
|
||||||
|
|
||||||
const showFlag = true;
|
const showFlag = true;
|
||||||
|
|
||||||
|
const parsedData = parsePublicNote(public_note);
|
||||||
|
|
||||||
|
let daysLeft = 0;
|
||||||
|
let isNeverExpire = false;
|
||||||
|
|
||||||
|
if (parsedData?.billingDataMod?.endDate) {
|
||||||
|
if (parsedData.billingDataMod.endDate.startsWith("0000-00-00")) {
|
||||||
|
isNeverExpire = true;
|
||||||
|
} else {
|
||||||
|
daysLeft = getDaysBetweenDates(
|
||||||
|
parsedData.billingDataMod.endDate,
|
||||||
|
new Date().toISOString(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return online ? (
|
return online ? (
|
||||||
<section>
|
<section>
|
||||||
<Card
|
<Card
|
||||||
@ -54,7 +76,7 @@ export default function ServerCard({
|
|||||||
>
|
>
|
||||||
{showFlag ? <ServerFlag country_code={country_code} /> : null}
|
{showFlag ? <ServerFlag country_code={country_code} /> : null}
|
||||||
</div>
|
</div>
|
||||||
<div className="relative">
|
<div className="relative flex flex-col">
|
||||||
<p
|
<p
|
||||||
className={cn(
|
className={cn(
|
||||||
"break-all font-bold tracking-tight",
|
"break-all font-bold tracking-tight",
|
||||||
@ -63,6 +85,20 @@ export default function ServerCard({
|
|||||||
>
|
>
|
||||||
{name}
|
{name}
|
||||||
</p>
|
</p>
|
||||||
|
{parsedData &&
|
||||||
|
(daysLeft >= 0 ? (
|
||||||
|
<p className={cn("text-[10px] text-muted-foreground")}>
|
||||||
|
剩余时间: {isNeverExpire ? "永久" : daysLeft + "天"}
|
||||||
|
</p>
|
||||||
|
) : (
|
||||||
|
<p
|
||||||
|
className={cn(
|
||||||
|
"text-[10px] text-muted-foreground text-red-600",
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
已过期: {daysLeft * -1} 天
|
||||||
|
</p>
|
||||||
|
))}
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<div className="flex flex-col gap-2">
|
<div className="flex flex-col gap-2">
|
||||||
@ -135,7 +171,7 @@ export default function ServerCard({
|
|||||||
className={cn(
|
className={cn(
|
||||||
"flex flex-col lg:min-h-[91px] min-h-[123px] items-center justify-start gap-3 p-3 md:px-5 lg:flex-row cursor-pointer hover:bg-accent/50 transition-colors",
|
"flex flex-col lg:min-h-[91px] min-h-[123px] items-center justify-start gap-3 p-3 md:px-5 lg:flex-row cursor-pointer hover:bg-accent/50 transition-colors",
|
||||||
)}
|
)}
|
||||||
onClick={() => navigate(`/server/${serverInfo.id}`)}
|
onClick={() => navigate(`/server/${serverInfo.id}`, { replace: true })}
|
||||||
>
|
>
|
||||||
<section
|
<section
|
||||||
className={cn("grid items-center gap-2 lg:w-40")}
|
className={cn("grid items-center gap-2 lg:w-40")}
|
||||||
|
@ -38,6 +38,7 @@ export function formatNezhaInfo(now: number, serverInfo: NezhaServer) {
|
|||||||
load_1: serverInfo.state.load_1?.toFixed(2) || 0.0,
|
load_1: serverInfo.state.load_1?.toFixed(2) || 0.0,
|
||||||
load_5: serverInfo.state.load_5?.toFixed(2) || 0.0,
|
load_5: serverInfo.state.load_5?.toFixed(2) || 0.0,
|
||||||
load_15: serverInfo.state.load_15?.toFixed(2) || 0.0,
|
load_15: serverInfo.state.load_15?.toFixed(2) || 0.0,
|
||||||
|
public_note: handlePublicNote(serverInfo.id, serverInfo.public_note || ""),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,9 +48,7 @@ export function getDaysBetweenDates(date1: string, date2: string): number {
|
|||||||
const secondDate = new Date(date2);
|
const secondDate = new Date(date2);
|
||||||
|
|
||||||
// 计算两个日期之间的天数差异
|
// 计算两个日期之间的天数差异
|
||||||
return Math.round(
|
return Math.round((firstDate.getTime() - secondDate.getTime()) / oneDay);
|
||||||
Math.abs((firstDate.getTime() - secondDate.getTime()) / oneDay),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const fetcher = (url: string) =>
|
export const fetcher = (url: string) =>
|
||||||
@ -115,3 +114,73 @@ export function formatTime(timestamp: number): string {
|
|||||||
const seconds = date.getSeconds().toString().padStart(2, "0");
|
const seconds = date.getSeconds().toString().padStart(2, "0");
|
||||||
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
|
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface BillingData {
|
||||||
|
startDate: string;
|
||||||
|
endDate: string;
|
||||||
|
autoRenewal: string;
|
||||||
|
cycle: string;
|
||||||
|
amount: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface PlanData {
|
||||||
|
bandwidth: string;
|
||||||
|
trafficVol: string;
|
||||||
|
trafficType: string;
|
||||||
|
IPv4: string;
|
||||||
|
IPv6: string;
|
||||||
|
networkRoute: string;
|
||||||
|
extra: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface PublicNoteData {
|
||||||
|
billingDataMod: BillingData;
|
||||||
|
planDataMod: PlanData;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function parsePublicNote(publicNote: string): PublicNoteData | null {
|
||||||
|
try {
|
||||||
|
if (!publicNote) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const data = JSON.parse(publicNote);
|
||||||
|
return {
|
||||||
|
billingDataMod: {
|
||||||
|
startDate: data.billingDataMod.startDate,
|
||||||
|
endDate: data.billingDataMod.endDate,
|
||||||
|
autoRenewal: data.billingDataMod.autoRenewal,
|
||||||
|
cycle: data.billingDataMod.cycle,
|
||||||
|
amount: data.billingDataMod.amount,
|
||||||
|
},
|
||||||
|
planDataMod: {
|
||||||
|
bandwidth: data.planDataMod.bandwidth,
|
||||||
|
trafficVol: data.planDataMod.trafficVol,
|
||||||
|
trafficType: data.planDataMod.trafficType,
|
||||||
|
IPv4: data.planDataMod.IPv4,
|
||||||
|
IPv6: data.planDataMod.IPv6,
|
||||||
|
networkRoute: data.planDataMod.networkRoute,
|
||||||
|
extra: data.planDataMod.extra,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error parsing public note:", error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to handle public_note with sessionStorage
|
||||||
|
export function handlePublicNote(serverId: number, publicNote: string): string {
|
||||||
|
const storageKey = `server_${serverId}_public_note`;
|
||||||
|
const storedNote = sessionStorage.getItem(storageKey);
|
||||||
|
|
||||||
|
if (!publicNote && storedNote) {
|
||||||
|
return storedNote;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (publicNote) {
|
||||||
|
sessionStorage.setItem(storageKey, publicNote);
|
||||||
|
return publicNote;
|
||||||
|
}
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
@ -6,6 +6,7 @@ export interface NezhaWebsocketResponse {
|
|||||||
export interface NezhaServer {
|
export interface NezhaServer {
|
||||||
id: number;
|
id: number;
|
||||||
name: string;
|
name: string;
|
||||||
|
public_note: string;
|
||||||
last_active: string;
|
last_active: string;
|
||||||
country_code: string;
|
country_code: string;
|
||||||
host: NezhaServerHost;
|
host: NezhaServerHost;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user