2026-04-01 00:58:42 +08:00
|
|
|
import dayjs from "dayjs";
|
|
|
|
|
|
|
|
|
|
import { i18n } from "@/i18n";
|
|
|
|
|
|
|
|
|
|
const generateStatusMap: Record<string, { label: string; color: string }> = {
|
|
|
|
|
draft: { label: "status.generate.draft", color: "default" },
|
2026-04-02 21:16:12 +08:00
|
|
|
queued: { label: "status.generate.queued", color: "processing" },
|
2026-04-01 00:58:42 +08:00
|
|
|
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<string, { label: string; color: string }> = {
|
|
|
|
|
unpublished: { label: "status.publish.unpublished", color: "default" },
|
|
|
|
|
publishing: { label: "status.publish.publishing", color: "processing" },
|
2026-04-03 00:39:15 +08:00
|
|
|
success: { label: "status.publish.success", color: "success" },
|
|
|
|
|
failed: { label: "status.publish.failed", color: "error" },
|
|
|
|
|
partial_success: { label: "status.publish.partial_success", color: "warning" },
|
2026-04-01 00:58:42 +08:00
|
|
|
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" },
|
2026-04-20 11:44:47 +08:00
|
|
|
pending_review: { label: "status.publish.failed", color: "error" },
|
2026-04-01 00:58:42 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-16 20:40:41 +08:00
|
|
|
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));
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-01 00:58:42 +08:00
|
|
|
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" };
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-02 21:16:12 +08:00
|
|
|
export function getSourceTypeLabel(sourceType?: string | null, generationMode?: string | null): string {
|
2026-04-01 00:58:42 +08:00
|
|
|
if (!sourceType) {
|
|
|
|
|
return "--";
|
|
|
|
|
}
|
|
|
|
|
if (sourceType === "template") {
|
|
|
|
|
return i18n.global.t("status.sourceType.template");
|
|
|
|
|
}
|
2026-04-06 22:18:55 +08:00
|
|
|
if (sourceType === "free_create") {
|
|
|
|
|
return i18n.global.t("status.sourceType.free_create");
|
|
|
|
|
}
|
2026-04-17 15:19:11 +08:00
|
|
|
if (sourceType === "kol") {
|
|
|
|
|
return i18n.global.t("status.sourceType.kol");
|
|
|
|
|
}
|
2026-04-02 21:16:12 +08:00
|
|
|
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");
|
|
|
|
|
}
|
2026-04-01 00:58:42 +08:00
|
|
|
return sourceType;
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-02 21:16:12 +08:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-01 00:58:42 +08:00
|
|
|
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`),
|
|
|
|
|
};
|
|
|
|
|
}
|