'use client'; import { memo } from 'react'; import { TestCaseStatusBadge } from './TestCaseStatusBadge'; import { getTestCaseActualHours, getTestCaseEstimateHours, needsTestCaseClaim } from '@/lib/test-case'; import { formatWorkHours } from '@/lib/work-hours'; import { formatDateTimeShort } from '@/lib/format'; import type { TestCase } from '@/lib/test-case'; import type { TaskCategory } from '@/lib/task-category'; interface Props { testCase: TestCase; category?: TaskCategory; categoryLabelWidthEm?: number; bugCount: number; onClick?: () => void; } const PRIORITY_DOT: Record = { P0: 'bg-red-500', P1: 'bg-orange-400', P2: 'bg-blue-400', P3: 'bg-zinc-300', }; function TestCaseRowImpl({ testCase, category, categoryLabelWidthEm, bugCount, onClick }: Props) { const estimateHours = getTestCaseEstimateHours(testCase); const actualHours = getTestCaseActualHours(testCase); const needsClaim = needsTestCaseClaim(testCase); const labelWidthStyle = categoryLabelWidthEm ? { width: `${categoryLabelWidthEm}em` } : undefined; const hasExecutorEstimate = typeof testCase.estimateHours === 'number' && testCase.estimateHours > 0; const hasAiEstimate = typeof testCase.aiEstimateHours === 'number' && testCase.aiEstimateHours > 0; const estimatePrefix = hasExecutorEstimate ? '执行预' : hasAiEstimate ? 'AI预' : '预'; const planText = testCase.plannedTestAt && testCase.plannedEndAt ? `${formatDateTimeShort(testCase.plannedTestAt)} → ${formatDateTimeShort(testCase.plannedEndAt)}` : testCase.plannedTestAt ? formatDateTimeShort(testCase.plannedTestAt) : ''; return (
{testCase.caseNo}
{testCase.title} {planText && ( {planText} )} {actualHours > 0 ? `${formatWorkHours(actualHours)} / ${formatWorkHours(estimateHours)}` : `${estimatePrefix} ${formatWorkHours(estimateHours)}`}
{bugCount > 0 && ( {bugCount} Bug )} {testCase.aiDraft && ( AI 草案 )} {!needsClaim && ( 负责人:{testCase.assigneeId} )} {needsClaim ? ( 待领取 ) : ( )} {category?.name || '未分类'}
); } export const TestCaseRow = memo(TestCaseRowImpl);