'use client'; import Link from 'next/link'; import { ArrowLeft, CheckCircle2, MessageSquare } from 'lucide-react'; import { TaskRuntimeStatusBadge, formatTaskRuntimeDuration, formatTaskRuntimeTime } from '@/components/task-runtime/TaskRuntimeShared'; import { Badge } from '@/components/ui/badge'; import { Button } from '@/components/ui/button'; import { pickAppText } from '@/lib/i18n/core'; import { useAppI18n } from '@/lib/i18n/provider'; import type { TaskRuntimeStatus } from '@/lib/task-runtime'; import type { BackendTask } from '@/types'; type Props = { task: BackendTask; activeLabel: string; durationMs: number | null; reviewTargetId?: string; }; const RUNTIME_STATUSES = new Set(['queued', 'running', 'waiting', 'blocked', 'done', 'error', 'cancelled']); function isRuntimeStatus(status: string): status is TaskRuntimeStatus { return RUNTIME_STATUSES.has(status); } function humanTaskStatus(status: string, locale: string) { const map: Record = { open: ['已创建', 'Open'], running: ['执行中', 'Running'], awaiting_acceptance: ['等待验收', 'Awaiting acceptance'], needs_revision: ['需要修改', 'Needs revision'], closed: ['已完成', 'Closed'], abandoned: ['已放弃', 'Abandoned'], }; const item = map[status]; return item ? pickAppText(locale, item[0], item[1]) : status; } export function TaskLiveHeader({ task, activeLabel, durationMs, reviewTargetId }: Props) { const { locale } = useAppI18n(); const title = task.short_title || String(task.metadata?.short_title || '') || task.description || task.goal || task.task_id; const showReviewLink = Boolean(reviewTargetId && ['awaiting_acceptance', 'needs_revision'].includes(task.status)); return (
{isRuntimeStatus(task.status) ? ( ) : ( {humanTaskStatus(task.status, locale)} )} {activeLabel ? {activeLabel} : null} {showReviewLink ? ( ) : null}

{title}

{task.description && task.description !== title ? (

{task.description}

) : null}
{pickAppText(locale, '更新', 'Updated')}: {formatTaskRuntimeTime(task.updated_at, locale)} {pickAppText(locale, '耗时', 'Duration')}: {formatTaskRuntimeDuration(durationMs, locale)}
); }