mirror of
https://github.com/Sagit-chu/flvx.git
synced 2026-10-13 04:36:37 +08:00
feat(nodes): add renewal cycle and auto-advance scheduling (#296)
- Add renewal_cycle field to nodes for tracking paid vs free cycles - Implement auto-advance scheduling when renewal is processed - Add migration test for renewal_cycle column - Update dashboard to show renewal cycle count - Add renewal status display on node detail page
This commit is contained in:
@@ -9,6 +9,7 @@ import {
|
||||
getUserPackageInfo,
|
||||
type AnnouncementData,
|
||||
} from "@/api";
|
||||
import { getNodeRenewalSnapshot } from "@/pages/node/renewal";
|
||||
import { getAdminFlag } from "@/utils/session";
|
||||
|
||||
export interface DashboardUserInfo {
|
||||
@@ -59,8 +60,17 @@ export interface DashboardNodeExpiryItem {
|
||||
remark?: string;
|
||||
tags?: string;
|
||||
expiryTime?: number;
|
||||
renewalCycle?: "month" | "quarter" | "year" | "";
|
||||
}
|
||||
|
||||
const normalizeDashboardRenewalCycle = (
|
||||
value: unknown,
|
||||
): DashboardNodeExpiryItem["renewalCycle"] => {
|
||||
return value === "month" || value === "quarter" || value === "year"
|
||||
? value
|
||||
: "";
|
||||
};
|
||||
|
||||
const DASHBOARD_POLL_INTERVAL_MS = 5000;
|
||||
const EXPIRATION_NOTIFICATION_STORAGE_KEY =
|
||||
"dashboard:last-expiration-notification";
|
||||
@@ -213,16 +223,25 @@ const normalizeNodeExpiryReminders = (items: NodeApiItem[]) => {
|
||||
name: item.name || "",
|
||||
remark: typeof item.remark === "string" ? item.remark : "",
|
||||
tags: typeof item.tags === "string" ? item.tags : "",
|
||||
renewalCycle: normalizeDashboardRenewalCycle(item.renewalCycle),
|
||||
expiryTime:
|
||||
typeof item.expiryTime === "number" && item.expiryTime > 0
|
||||
? item.expiryTime
|
||||
: undefined,
|
||||
}))
|
||||
.filter((item) => {
|
||||
if (!item.expiryTime) return false;
|
||||
return item.expiryTime <= now + warningWindowMs;
|
||||
if (!item.expiryTime || !item.renewalCycle) return false;
|
||||
const snapshot = getNodeRenewalSnapshot(item.expiryTime, item.renewalCycle);
|
||||
|
||||
if (!snapshot.nextDueTime) return false;
|
||||
return snapshot.nextDueTime <= now + warningWindowMs;
|
||||
})
|
||||
.sort((a, b) => (a.expiryTime || 0) - (b.expiryTime || 0));
|
||||
.sort((a, b) => {
|
||||
const aDue = getNodeRenewalSnapshot(a.expiryTime, a.renewalCycle).nextDueTime || 0;
|
||||
const bDue = getNodeRenewalSnapshot(b.expiryTime, b.renewalCycle).nextDueTime || 0;
|
||||
|
||||
return aDue - bDue;
|
||||
});
|
||||
};
|
||||
|
||||
export const useDashboardData = (): DashboardDataState => {
|
||||
|
||||
Reference in New Issue
Block a user