import dayjs from "dayjs"; import { i18n } from "@/i18n"; const generateStatusMap: Record = { draft: { label: "status.generate.draft", color: "default" }, queued: { label: "status.generate.queued", color: "processing" }, generating: { label: "status.generate.generating", color: "processing" }, running: { label: "status.generate.running", color: "processing" }, completed: { label: "status.generate.completed", color: "success" }, failed: { label: "status.generate.failed", color: "error" }, }; const publishStatusMap: Record = { unpublished: { label: "status.publish.unpublished", color: "default" }, publishing: { label: "status.publish.publishing", color: "processing" }, success: { label: "status.publish.success", color: "success" }, failed: { label: "status.publish.failed", color: "error" }, partial_success: { label: "status.publish.partial_success", color: "warning" }, published: { label: "status.publish.published", color: "success" }, publish_success: { label: "status.publish.publish_success", color: "success" }, publish_failed: { label: "status.publish.publish_failed", color: "error" }, pending_review: { label: "status.publish.failed", color: "error" }, }; export function formatDateTime(value?: string | null, pattern = "YYYY-MM-DD HH:mm"): string { if (!value) { return "--"; } const parsed = dayjs(value); return parsed.isValid() ? parsed.format(pattern) : value; } export function formatBytes(bytes: number, decimals = 2): string { if (bytes === 0) return "0 B"; const k = 1024; const dm = decimals < 0 ? 0 : decimals; const sizes = ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"]; const i = Math.floor(Math.log(bytes) / Math.log(k)); return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + " " + sizes[i]; } export function formatPercentage(value?: number | null, decimals = 2): string { if (typeof value !== "number" || Number.isNaN(value) || !Number.isFinite(value)) { return "--"; } return value.toFixed(Math.max(0, decimals)); } export function getGenerateStatusMeta(status?: string | null): { label: string; color: string } { if (!status) { return { label: "--", color: "default" }; } const meta = generateStatusMap[status]; return meta ? { label: i18n.global.t(meta.label), color: meta.color } : { label: status, color: "default" }; } export function getPublishStatusMeta(status?: string | null): { label: string; color: string } { if (!status) { return { label: "--", color: "default" }; } const meta = publishStatusMap[status]; return meta ? { label: i18n.global.t(meta.label), color: meta.color } : { label: status, color: "default" }; } export function getSourceTypeLabel(sourceType?: string | null, generationMode?: string | null): string { if (!sourceType) { return "--"; } if (sourceType === "template") { return i18n.global.t("status.sourceType.template"); } if (sourceType === "free_create") { return i18n.global.t("status.sourceType.free_create"); } if (sourceType === "kol") { return i18n.global.t("status.sourceType.kol"); } if (sourceType === "custom_generation") { if (generationMode === "schedule") { return i18n.global.t("status.sourceType.schedule_task"); } if (generationMode === "instant") { return i18n.global.t("status.sourceType.instant_task"); } return i18n.global.t("status.sourceType.custom_generation"); } return sourceType; } export function formatCronExecutionTime(cronExpr?: string | null): string { if (!cronExpr) { return "--"; } const fiveFieldMatch = cronExpr.match(/^(\d{1,2})\s+(\d{1,2})\s+\*\s+\*\s+\*$/); if (fiveFieldMatch) { const [, minute, hour] = fiveFieldMatch; return `${hour.padStart(2, "0")}:${minute.padStart(2, "0")}`; } const sixFieldMatch = cronExpr.match(/^(\d{1,2})\s+(\d{1,2})\s+(\d{1,2})\s+\*\s+\*\s+\*$/); if (sixFieldMatch) { const [, second, minute, hour] = sixFieldMatch; return `${hour.padStart(2, "0")}:${minute.padStart(2, "0")}:${second.padStart(2, "0")}`; } return cronExpr; } export function getTemplateMeta(templateKey: string): { eyebrow: string; helper: string; accent: string; action: string; } { const key = [ "top_x_article", "product_review", "research_report", "brand_search_expansion", ].includes(templateKey) ? templateKey : "default"; return { eyebrow: i18n.global.t(`templateMeta.${key}.eyebrow`), helper: i18n.global.t(`templateMeta.${key}.helper`), accent: i18n.global.t(`templateMeta.${key}.accent`), action: i18n.global.t(`templateMeta.${key}.action`), }; }