Files
flvx/vite-frontend/src/pages/node/renewal.ts
T

119 lines
2.5 KiB
TypeScript

export type NodeRenewalCycle = "" | "month" | "quarter" | "year";
export interface NodeRenewalSnapshot {
cycle: NodeRenewalCycle;
anchorTime?: number;
nextDueTime?: number;
diffDays?: number;
state: "unset" | "expired" | "dueSoon" | "scheduled";
label: string;
}
const addMonths = (timestamp: number, months: number): number => {
const date = new Date(timestamp);
const next = new Date(date);
next.setMonth(next.getMonth() + months);
return next.getTime();
};
const cycleToMonths = (cycle: NodeRenewalCycle): number => {
switch (cycle) {
case "month":
return 1;
case "quarter":
return 3;
case "year":
return 12;
default:
return 0;
}
};
export const getNodeRenewalCycleLabel = (cycle?: string): string => {
switch (cycle) {
case "month":
return "月付";
case "quarter":
return "季付";
case "year":
return "年付";
default:
return "未设置";
}
};
export const getNodeRenewalSnapshot = (
anchorTime?: number,
cycle?: string,
warningDays = 7,
): NodeRenewalSnapshot => {
const normalizedCycle =
cycle === "month" || cycle === "quarter" || cycle === "year" ? cycle : "";
if (!anchorTime || anchorTime <= 0 || !normalizedCycle) {
return {
cycle: normalizedCycle,
anchorTime: anchorTime && anchorTime > 0 ? anchorTime : undefined,
state: "unset",
label: "未设置续费周期",
};
}
const intervalMonths = cycleToMonths(normalizedCycle);
let nextDueTime = anchorTime;
while (nextDueTime < Date.now()) {
const advanced = addMonths(nextDueTime, intervalMonths);
if (advanced === nextDueTime) {
break;
}
nextDueTime = advanced;
}
const diffDays = Math.ceil(
(nextDueTime - Date.now()) / (1000 * 60 * 60 * 24),
);
if (diffDays <= 0) {
return {
cycle: normalizedCycle,
anchorTime,
nextDueTime,
diffDays,
state: "expired",
label: "今天到期",
};
}
if (diffDays <= warningDays) {
return {
cycle: normalizedCycle,
anchorTime,
nextDueTime,
diffDays,
state: "dueSoon",
label: diffDays === 1 ? "明天续费" : `${diffDays}天后续费`,
};
}
return {
cycle: normalizedCycle,
anchorTime,
nextDueTime,
diffDays,
state: "scheduled",
label: `${diffDays}天后续费`,
};
};
export const formatNodeRenewalTime = (timestamp?: number): string => {
if (!timestamp || timestamp <= 0) {
return "未设置";
}
return new Date(timestamp).toLocaleString();
};