import type { Job, JobStatus } from "../domain/types"; /** 任務類型顯示名(中文) */ export function jobTemplateLabel( templateType: string, t: (key: string, params?: Record) => string, ): string { switch (templateType) { case "demo": return t("jobs.demoLabel"); case "threads_token_renew": return t("jobs.template.tokenRenew"); case "persona_analyze_account": return t("jobs.template.personaAnalyzeAccount"); case "persona_analyze_text": return t("jobs.template.personaAnalyzeText"); case "compose_mimic": return t("jobs.template.composeMimic"); case "play_generate_script": return t("jobs.template.playGenerateScript"); default: return templateType || t("jobs.template.unknown"); } } /** 是否為約每 30 天的定期 Token 延長任務 */ export function isRecurringTokenRenew(job: { template_type: string }): boolean { return job.template_type === "threads_token_renew"; } /** * 是否應在頂欄/加速輪詢中視為「即時進行中」: * - running 一律 * - pending/queued 且已到期(run_after 空或 ≤ now)— 不含遠期排程(如 30 天後 token 延長) */ export function isJobLiveActive( job: { status: string; run_after?: number }, nowNs: number = Date.now() * 1_000_000, ): boolean { if (job.status === "running") return true; if (job.status !== "pending" && job.status !== "queued") return false; if (!job.run_after || job.run_after <= 0) return true; return job.run_after <= nowNs; } /** 執行中不可手動刪除;其餘(含已排程/終態)可刪 */ export function canDeleteJob(job: { status: string }): boolean { return job.status !== "running"; } /** 狀態中文 */ export function jobStatusLabel( status: JobStatus | string, t: (key: string, params?: Record) => string, ): string { const key = `jobs.status.${status}`; const label = t(key); // 若缺 key,i18n 常回傳 key 本身 if (label === key) return status; return label; } export function jobStatusTone( status: JobStatus | string, ): "success" | "danger" | "warning" | "brand" | "neutral" { switch (status) { case "succeeded": return "success"; case "failed": return "danger"; case "cancelled": case "cancel_requested": return "neutral"; case "running": return "brand"; case "queued": case "pending": return "warning"; default: return "neutral"; } } /** * 副標:定期節奏(約每 30 天)+ 進度摘要 + 下次執行時間。 * 標題已含「約每 30 天」;此處再強調一次節奏,方便列表一眼辨認。 */ export function jobSubtitle( job: Job, t: (key: string, params?: Record) => string, formatTime: (n: number | null | undefined) => string, ): string { const parts: string[] = []; if (isRecurringTokenRenew(job)) { parts.push(t("jobs.template.tokenRenewCadence")); } if (job.progress_summary) { parts.push(job.progress_summary); } if ( job.run_after && job.run_after > 0 && (job.status === "queued" || job.status === "pending") ) { parts.push(t("jobs.nextRun", { time: formatTime(job.run_after) })); } return parts.join(" · "); }