From 407332c938ea57c67747895bc30a0cfa86506ddb Mon Sep 17 00:00:00 2001 From: hamster1963 <1410514192@qq.com> Date: Thu, 19 Dec 2024 13:48:13 +0800 Subject: [PATCH] feat: refactor public note --- bun.lockb | Bin 184880 -> 185228 bytes package.json | 1 + src/components/PlanInfo.tsx | 69 +++++++++++++ src/components/RemainPercentBar.tsx | 21 ++++ src/components/ServerCard.tsx | 144 +++------------------------- src/components/ServerCardInline.tsx | 142 +++------------------------ src/components/billingInfo.tsx | 61 ++++++++++++ src/lib/utils.ts | 109 ++++++++++++++++++++- 8 files changed, 285 insertions(+), 262 deletions(-) create mode 100644 src/components/PlanInfo.tsx create mode 100644 src/components/RemainPercentBar.tsx create mode 100644 src/components/billingInfo.tsx diff --git a/bun.lockb b/bun.lockb index 9041504de22748fc6a89cdc58f84cfbd88651c31..3438f771eefb1477cb98b21eafeb28d71c40572e 100755 GIT binary patch delta 23284 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 GM*I)W%IjGG delta 22873 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 UWA%|De2VdObkVfi^_Hps1Db~1WB>pF diff --git a/package.json b/package.json index 9d60199..32508b2 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,7 @@ "clsx": "^2.1.1", "country-flag-icons": "^1.5.13", "d3-geo": "^3.1.1", + "dayjs": "^1.11.13", "framer-motion": "^12.0.0-alpha.2", "i18next": "^24.1.0", "lucide-react": "^0.460.0", diff --git a/src/components/PlanInfo.tsx b/src/components/PlanInfo.tsx new file mode 100644 index 0000000..5d5b7c3 --- /dev/null +++ b/src/components/PlanInfo.tsx @@ -0,0 +1,69 @@ +import { PublicNoteData, cn } from "@/lib/utils" + +export default function PlanInfo({ parsedData }: { parsedData: PublicNoteData }) { + if (!parsedData || !parsedData.planDataMod) { + return null + } + return ( +
+ {parsedData.planDataMod.bandwidth !== "" && ( +

+ {parsedData.planDataMod.bandwidth} +

+ )} + {parsedData.planDataMod.trafficVol !== "" && ( +

+ {parsedData.planDataMod.trafficVol} +

+ )} + {parsedData.planDataMod.IPv4 === "1" && ( +

+ IPv4 +

+ )} + {parsedData.planDataMod.IPv6 === "1" && ( +

+ IPv6 +

+ )} + {parsedData.planDataMod.networkRoute && ( +

+ {parsedData.planDataMod.networkRoute.split(",").map((route) => { + return route + })} +

+ )} + {parsedData.planDataMod.extra && ( +

+ {parsedData.planDataMod.extra.split(",").map((extra) => { + return extra + })} +

+ )} +
+ ) +} diff --git a/src/components/RemainPercentBar.tsx b/src/components/RemainPercentBar.tsx new file mode 100644 index 0000000..0cb4d93 --- /dev/null +++ b/src/components/RemainPercentBar.tsx @@ -0,0 +1,21 @@ +import { cn } from "@/lib/utils" + +import { Progress } from "./ui/progress" + +export default function RemainPercentBar({ + value, + className, +}: { + value: number + className?: string +}) { + return ( + + ) +} diff --git a/src/components/ServerCard.tsx b/src/components/ServerCard.tsx index 868ad25..ec4a6ba 100644 --- a/src/components/ServerCard.tsx +++ b/src/components/ServerCard.tsx @@ -1,11 +1,13 @@ import ServerFlag from "@/components/ServerFlag" import ServerUsageBar from "@/components/ServerUsageBar" import { formatBytes } from "@/lib/format" -import { cn, formatNezhaInfo, getDaysBetweenDates, parsePublicNote } from "@/lib/utils" +import { cn, formatNezhaInfo, parsePublicNote } from "@/lib/utils" import { NezhaServer } from "@/types/nezha-api" import { useTranslation } from "react-i18next" import { useNavigate } from "react-router-dom" +import PlanInfo from "./PlanInfo" +import BillingInfo from "./billingInfo" import { Badge } from "./ui/badge" import { Card } from "./ui/card" @@ -37,17 +39,6 @@ export default function ServerCard({ now, serverInfo }: { now: number; serverInf 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(now).toISOString()) - } - } - return online ? ( {name}

- {parsedData?.billingDataMod && - (daysLeft >= 0 ? ( - <> -

- 剩余时间: {isNeverExpire ? "永久" : daysLeft + "天"} -

- {parsedData.billingDataMod.amount && - parsedData.billingDataMod.amount !== "0" && - parsedData.billingDataMod.amount !== "-1" ? ( -

- 价格: {parsedData.billingDataMod.amount}/{parsedData.billingDataMod.cycle} -

- ) : parsedData.billingDataMod.amount === "0" ? ( -

免费

- ) : parsedData.billingDataMod.amount === "-1" ? ( -

按量收费

- ) : null} - - ) : ( - <> -

- 已过期: {daysLeft * -1} 天 -

- {parsedData.billingDataMod.amount && - parsedData.billingDataMod.amount !== "0" && - parsedData.billingDataMod.amount !== "-1" ? ( -

- 价格: {parsedData.billingDataMod.amount}/{parsedData.billingDataMod.cycle} -

- ) : parsedData.billingDataMod.amount === "0" ? ( -

免费

- ) : parsedData.billingDataMod.amount === "-1" ? ( -

按量收费

- ) : null} - - ))} - {parsedData?.planDataMod && ( -
- {parsedData.planDataMod.bandwidth !== "" && ( -

- {parsedData.planDataMod.bandwidth} -

- )} - {parsedData.planDataMod.trafficVol !== "" && ( -

- {parsedData.planDataMod.trafficVol} -

- )} -
- )} + {parsedData?.billingDataMod && }
@@ -188,12 +122,13 @@ export default function ServerCard({ now, serverInfo }: { now: number; serverInf )} + {parsedData?.planDataMod && }
) : ( : null}
-

+

{name}

- {parsedData?.billingDataMod && - (daysLeft >= 0 ? ( - <> -

- 剩余时间: {isNeverExpire ? "永久" : daysLeft + "天"} -

- {parsedData.billingDataMod.amount && - parsedData.billingDataMod.amount !== "0" && - parsedData.billingDataMod.amount !== "-1" ? ( -

- 价格: {parsedData.billingDataMod.amount}/{parsedData.billingDataMod.cycle} -

- ) : parsedData.billingDataMod.amount === "0" ? ( -

免费

- ) : parsedData.billingDataMod.amount === "-1" ? ( -

按量收费

- ) : null} - - ) : ( - <> -

- 已过期: {daysLeft * -1} 天 -

- {parsedData.billingDataMod.amount && - parsedData.billingDataMod.amount !== "0" && - parsedData.billingDataMod.amount !== "-1" ? ( -

- 价格: {parsedData.billingDataMod.amount}/{parsedData.billingDataMod.cycle} -

- ) : parsedData.billingDataMod.amount === "0" ? ( -

免费

- ) : parsedData.billingDataMod.amount === "-1" ? ( -

按量收费

- ) : null} - - ))} - {parsedData?.planDataMod && ( -
- {parsedData.planDataMod.bandwidth !== "" && ( -

- {parsedData.planDataMod.bandwidth} -

- )} - {parsedData.planDataMod.trafficVol !== "" && ( -

- {parsedData.planDataMod.trafficVol} -

- )} -
- )} + {parsedData?.billingDataMod && }
+ {parsedData?.planDataMod && }
) } diff --git a/src/components/ServerCardInline.tsx b/src/components/ServerCardInline.tsx index 037d6b1..3a2a8cc 100644 --- a/src/components/ServerCardInline.tsx +++ b/src/components/ServerCardInline.tsx @@ -2,11 +2,13 @@ import ServerFlag from "@/components/ServerFlag" import ServerUsageBar from "@/components/ServerUsageBar" import { formatBytes } from "@/lib/format" import { GetFontLogoClass, GetOsName, MageMicrosoftWindows } from "@/lib/logo-class" -import { cn, formatNezhaInfo, getDaysBetweenDates, parsePublicNote } from "@/lib/utils" +import { cn, formatNezhaInfo, parsePublicNote } from "@/lib/utils" import { NezhaServer } from "@/types/nezha-api" import { useTranslation } from "react-i18next" import { useNavigate } from "react-router-dom" +import PlanInfo from "./PlanInfo" +import BillingInfo from "./billingInfo" import { Card } from "./ui/card" import { Separator } from "./ui/separator" @@ -43,17 +45,6 @@ export default function ServerCardInline({ 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(now).toISOString()) - } - } - return online ? (
{name}

- {parsedData?.billingDataMod && - (daysLeft >= 0 ? ( - <> -

- 剩余时间: {isNeverExpire ? "永久" : daysLeft + "天"} -

- {parsedData.billingDataMod.amount && - parsedData.billingDataMod.amount !== "0" && - parsedData.billingDataMod.amount !== "-1" ? ( -

- 价格: {parsedData.billingDataMod.amount}/{parsedData.billingDataMod.cycle} -

- ) : parsedData.billingDataMod.amount === "0" ? ( -

免费

- ) : parsedData.billingDataMod.amount === "-1" ? ( -

按量收费

- ) : null} - - ) : ( - <> -

- 已过期: {daysLeft * -1} 天 -

- {parsedData.billingDataMod.amount && - parsedData.billingDataMod.amount !== "0" && - parsedData.billingDataMod.amount !== "-1" ? ( -

- 价格: {parsedData.billingDataMod.amount}/{parsedData.billingDataMod.cycle} -

- ) : parsedData.billingDataMod.amount === "0" ? ( -

免费

- ) : parsedData.billingDataMod.amount === "-1" ? ( -

按量收费

- ) : null} - - ))} - {parsedData?.planDataMod && ( -
- {parsedData.planDataMod.bandwidth !== "" && ( -

- {parsedData.planDataMod.bandwidth} -

- )} - {parsedData.planDataMod.trafficVol !== "" && ( -

- {parsedData.planDataMod.trafficVol} -

- )} -
- )} + {parsedData?.billingDataMod && }
-
+
@@ -221,13 +155,14 @@ export default function ServerCardInline({
+ {parsedData?.planDataMod && }
) : ( navigate(`/server/${serverInfo.id}`)} >
@@ -253,66 +188,11 @@ export default function ServerCardInline({ > {name}

- {parsedData?.billingDataMod && - (daysLeft >= 0 ? ( - <> -

- 剩余时间: {isNeverExpire ? "永久" : daysLeft + "天"} -

- {parsedData.billingDataMod.amount && - parsedData.billingDataMod.amount !== "0" && - parsedData.billingDataMod.amount !== "-1" ? ( -

- 价格: {parsedData.billingDataMod.amount}/{parsedData.billingDataMod.cycle} -

- ) : parsedData.billingDataMod.amount === "0" ? ( -

免费

- ) : parsedData.billingDataMod.amount === "-1" ? ( -

按量收费

- ) : null} - - ) : ( - <> -

- 已过期: {daysLeft * -1} 天 -

- {parsedData.billingDataMod.amount && - parsedData.billingDataMod.amount !== "0" && - parsedData.billingDataMod.amount !== "-1" ? ( -

- 价格: {parsedData.billingDataMod.amount}/{parsedData.billingDataMod.cycle} -

- ) : parsedData.billingDataMod.amount === "0" ? ( -

免费

- ) : parsedData.billingDataMod.amount === "-1" ? ( -

按量收费

- ) : null} - - ))} - {parsedData?.planDataMod && ( -
- {parsedData.planDataMod.bandwidth !== "" && ( -

- {parsedData.planDataMod.bandwidth} -

- )} - {parsedData.planDataMod.trafficVol !== "" && ( -

- {parsedData.planDataMod.trafficVol} -

- )} -
- )} + {parsedData?.billingDataMod && }
+ + {parsedData?.planDataMod && } ) } diff --git a/src/components/billingInfo.tsx b/src/components/billingInfo.tsx new file mode 100644 index 0000000..9a0affa --- /dev/null +++ b/src/components/billingInfo.tsx @@ -0,0 +1,61 @@ +import { PublicNoteData, cn, getDaysBetweenDatesWithAutoRenewal } from "@/lib/utils" + +import RemainPercentBar from "./RemainPercentBar" + +export default function BillingInfo({ parsedData }: { parsedData: PublicNoteData }) { + if (!parsedData || !parsedData.billingDataMod) { + return null + } + + let isNeverExpire = false + let daysLeftObject = { + days: 0, + cycleLabel: "", + remainingPercentage: 0, + } + + if (parsedData?.billingDataMod?.endDate) { + if (parsedData.billingDataMod.endDate.startsWith("0000-00-00")) { + isNeverExpire = true + } else { + daysLeftObject = getDaysBetweenDatesWithAutoRenewal(parsedData.billingDataMod) + } + } + + return daysLeftObject.days >= 0 ? ( + <> +
+ 剩余时间: {isNeverExpire ? "永久" : daysLeftObject.days + "天"} +
+ {parsedData.billingDataMod.amount && + parsedData.billingDataMod.amount !== "0" && + parsedData.billingDataMod.amount !== "-1" ? ( +

+ 价格: {parsedData.billingDataMod.amount}/{parsedData.billingDataMod.cycle} +

+ ) : parsedData.billingDataMod.amount === "0" ? ( +

免费

+ ) : parsedData.billingDataMod.amount === "-1" ? ( +

按量收费

+ ) : null} + + + ) : ( + <> +

+ 已过期: {daysLeftObject.days * -1} 天 +

+ {parsedData.billingDataMod.amount && + parsedData.billingDataMod.amount !== "0" && + parsedData.billingDataMod.amount !== "-1" ? ( +

+ 价格: {parsedData.billingDataMod.amount}/{parsedData.billingDataMod.cycle} +

+ ) : parsedData.billingDataMod.amount === "0" ? ( +

免费

+ ) : parsedData.billingDataMod.amount === "-1" ? ( +

按量收费

+ ) : null} + + ) +} diff --git a/src/lib/utils.ts b/src/lib/utils.ts index d04c9be..3777f5b 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -1,5 +1,6 @@ import { NezhaServer } from "@/types/nezha-api" import { type ClassValue, clsx } from "clsx" +import dayjs from "dayjs" import { twMerge } from "tailwind-merge" export function cn(...inputs: ClassValue[]) { @@ -46,6 +47,112 @@ export function formatNezhaInfo(now: number, serverInfo: NezhaServer) { } } +export function getDaysBetweenDatesWithAutoRenewal({ + autoRenewal, + cycle, + startDate, + endDate, +}: BillingData): { days: number; cycleLabel: string; remainingPercentage: number } { + let months = 1 + // 套餐资费 + let cycleLabel = cycle + + switch (cycle.toLowerCase()) { + case "月": + case "m": + case "mo": + case "month": + case "monthly": + cycleLabel = "月" + months = 1 + break + case "年": + case "y": + case "yr": + case "year": + case "annual": + cycleLabel = "年" + months = 12 + break + case "季": + case "quarterly": + cycleLabel = "季" + months = 3 + break + case "半": + case "半年": + case "h": + case "half": + case "semi-annually": + cycleLabel = "半年" + months = 6 + break + default: + cycleLabel = cycle + break + } + + const nowTime = new Date().getTime() + const endTime = dayjs(endDate).valueOf() + + if (autoRenewal !== "1") { + return { + days: getDaysBetweenDates(endDate, new Date(nowTime).toISOString()), + cycleLabel: cycleLabel, + remainingPercentage: + getDaysBetweenDates(endDate, new Date(nowTime).toISOString()) / + dayjs(endDate).diff(startDate, "day") > + 1 + ? 1 + : getDaysBetweenDates(endDate, new Date(nowTime).toISOString()) / + dayjs(endDate).diff(startDate, "day"), + } + } + + const nextTime = getNextCycleTime(endTime, months, nowTime) + const diff = dayjs(nextTime).diff(dayjs(), "day") + 1 + const remainingPercentage = diff / (30 * months) > 1 ? 1 : diff / (30 * months) + + console.log( + "nextTime", + nextTime, + "diff", + diff, + "month", + months, + "remainingPercentage", + remainingPercentage, + ) + + return { + days: diff, + cycleLabel: cycleLabel, + remainingPercentage: remainingPercentage, + } +} + +// Thanks to hi2shark for the code +// https://github.com/hi2shark/nazhua/blob/main/src/utils/date.js#L86 +export function getNextCycleTime(startDate: number, months: number, specifiedDate: number): number { + const start = dayjs(startDate) + const checkDate = dayjs(specifiedDate) + + if (!start.isValid() || months <= 0) { + throw new Error("参数无效:请检查起始日期、周期月份数和指定日期。") + } + + let nextDate = start + + // 循环增加周期直到大于当前日期 + let whileStatus = true + while (whileStatus) { + nextDate = nextDate.add(months, "month") + whileStatus = nextDate.valueOf() <= checkDate.valueOf() + } + + return nextDate.valueOf() // 返回时间毫秒数 +} + export function getDaysBetweenDates(date1: string, date2: string): number { const oneDay = 24 * 60 * 60 * 1000 // 一天的毫秒数 const firstDate = new Date(date1) @@ -137,7 +244,7 @@ interface PlanData { extra: string } -interface PublicNoteData { +export interface PublicNoteData { billingDataMod?: BillingData planDataMod?: PlanData }