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' }, partial_success: { label: 'status.generate.partial_success', color: 'warning' }, partial_completed: { label: 'status.generate.partial_completed', color: 'warning' }, 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.pending_review', color: 'warning' }, blocked_by_compliance: { label: 'status.publish.blocked_by_compliance', 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 hasActiveGenerationStatus(status?: string | null): boolean { return status === 'queued' || status === 'pending' || status === 'generating' || status === 'running' } 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 === 'imitation') { return i18n.global.t('status.sourceType.imitation') } 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`), } }