93 lines
2.5 KiB
TypeScript
93 lines
2.5 KiB
TypeScript
export const POINTS_SYSTEM_CONFIG_KEY = "points_system_config";
|
|
export const POINTS_PACKAGES_KEY = "points_packages";
|
|
|
|
export type PointsSystemConfig = {
|
|
enabled: boolean;
|
|
blockOnInsufficient: boolean;
|
|
creditCostPer3D: number;
|
|
};
|
|
|
|
export type PointsPackage = {
|
|
id: string;
|
|
name: string;
|
|
points: number;
|
|
price: number;
|
|
currency: string;
|
|
isEnabled: boolean;
|
|
};
|
|
|
|
export const defaultPointsSystemConfig: PointsSystemConfig = {
|
|
enabled: false,
|
|
blockOnInsufficient: true,
|
|
creditCostPer3D: 0,
|
|
};
|
|
|
|
export const defaultPointsPackages: PointsPackage[] = [
|
|
{
|
|
id: "starter-1000",
|
|
name: "入门包",
|
|
points: 1000,
|
|
price: 9.9,
|
|
currency: "CNY",
|
|
isEnabled: true,
|
|
},
|
|
{
|
|
id: "pro-5000",
|
|
name: "专业包",
|
|
points: 5000,
|
|
price: 39.9,
|
|
currency: "CNY",
|
|
isEnabled: true,
|
|
},
|
|
];
|
|
|
|
export function normalizePointsSystemConfig(value: unknown): PointsSystemConfig {
|
|
if (!value || typeof value !== "object") {
|
|
return defaultPointsSystemConfig;
|
|
}
|
|
|
|
const raw = value as Partial<PointsSystemConfig>;
|
|
const parsed3DCost = Number(raw.creditCostPer3D);
|
|
return {
|
|
enabled: raw.enabled === true,
|
|
blockOnInsufficient: raw.blockOnInsufficient !== false,
|
|
creditCostPer3D:
|
|
Number.isFinite(parsed3DCost) && parsed3DCost > 0
|
|
? Math.min(100000, Math.round(parsed3DCost))
|
|
: 0,
|
|
};
|
|
}
|
|
|
|
export function normalizePointsPackages(value: unknown): PointsPackage[] {
|
|
if (!Array.isArray(value)) {
|
|
return defaultPointsPackages;
|
|
}
|
|
|
|
const normalized = value
|
|
.map((item, index) => {
|
|
if (!item || typeof item !== "object") return null;
|
|
const raw = item as Partial<PointsPackage>;
|
|
const id = String(raw.id || `package-${index + 1}`).trim();
|
|
const name = String(raw.name || "").trim();
|
|
const points = Number(raw.points);
|
|
const price = Number(raw.price);
|
|
const currency = String(raw.currency || "CNY").trim().toUpperCase();
|
|
|
|
if (!id || !name || !Number.isFinite(points) || points <= 0) return null;
|
|
if (!Number.isFinite(price) || price < 0) return null;
|
|
|
|
return {
|
|
id: id.slice(0, 64),
|
|
name: name.slice(0, 64),
|
|
points: Math.round(points),
|
|
price: Number(price.toFixed(2)),
|
|
currency: currency.slice(0, 8) || "CNY",
|
|
isEnabled: raw.isEnabled !== false,
|
|
} satisfies PointsPackage;
|
|
})
|
|
.filter((item): item is PointsPackage => Boolean(item))
|
|
.slice(0, 30);
|
|
|
|
return normalized.length > 0 ? normalized : defaultPointsPackages;
|
|
}
|