feat(ai): 优化拆解重跑与结果展示
This commit is contained in:
@@ -183,7 +183,7 @@ export function DevTaskCreateModal({ versionId, requirementIds, versionDeadline,
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-[12px] text-[var(--ink-soft)] mb-1">预计工时(自动)</label>
|
||||
<label className="block text-[12px] text-[var(--ink-soft)] mb-1">执行预估工时(自动)</label>
|
||||
<div className="h-9 flex items-center px-3 rounded-lg border border-dashed border-[var(--line)] bg-[var(--bg-subtle)] text-[13px] text-[var(--ink-soft)] tabular-nums">
|
||||
{estimateHours > 0 ? formatWorkHours(estimateHours) : (startBeforeEnd ? '0h' : '请先选择有效起止时间')}
|
||||
</div>
|
||||
|
||||
@@ -50,6 +50,8 @@ export function DevTaskDetailDrawer({ taskId, allTaskIds, onClose, contextLabel
|
||||
const [showBlockInput, setShowBlockInput] = useState(false);
|
||||
|
||||
const estimate = useMemo(() => getEstimateHours(task), [task]);
|
||||
const executorEstimate = typeof task.estimateHours === 'number' && task.estimateHours > 0 ? task.estimateHours : undefined;
|
||||
const aiEstimate = typeof task.aiEstimateHours === 'number' && task.aiEstimateHours > 0 ? task.aiEstimateHours : undefined;
|
||||
const actual = useMemo(() => getActualHours(task), [task]);
|
||||
const overrun = actual > estimate && estimate > 0;
|
||||
const requireDelay = task.status === 'todo' && needsDelayReason(task);
|
||||
@@ -217,8 +219,12 @@ export function DevTaskDetailDrawer({ taskId, allTaskIds, onClose, contextLabel
|
||||
<span className="text-[var(--ink)] font-medium tabular-nums">{task.actualEndAt ? formatShortTime(task.actualEndAt) : '—'}</span>
|
||||
</div>
|
||||
<div className="flex flex-col gap-0.5">
|
||||
<span className="text-[10px] text-[var(--ink-muted)]">预计耗时</span>
|
||||
<span className="text-[var(--ink)] font-medium tabular-nums">{formatHours(estimate)}</span>
|
||||
<span className="text-[10px] text-[var(--ink-muted)]">AI 预估</span>
|
||||
<span className="text-[var(--ink)] font-medium tabular-nums">{aiEstimate ? formatHours(aiEstimate) : '—'}</span>
|
||||
</div>
|
||||
<div className="flex flex-col gap-0.5">
|
||||
<span className="text-[10px] text-[var(--ink-muted)]">执行预估</span>
|
||||
<span className="text-[var(--ink)] font-medium tabular-nums">{executorEstimate ? formatHours(executorEstimate) : '待负责人填写'}</span>
|
||||
</div>
|
||||
<div className="flex flex-col gap-0.5">
|
||||
<span className="text-[10px] text-[var(--ink-muted)]">实际耗时</span>
|
||||
|
||||
@@ -34,8 +34,11 @@ function timeRangeText(task: DevTask): { text: string; tone: string } {
|
||||
return { text: '', tone: 'text-[var(--ink-muted)]' };
|
||||
}
|
||||
|
||||
function hoursText(estimate: number, actual: number): { text: string; tone: string } {
|
||||
if (actual <= 0) return { text: `预 ${formatWorkHours(estimate)}`, tone: 'text-[var(--ink-muted)]' };
|
||||
function hoursText(task: DevTask, estimate: number, actual: number): { text: string; tone: string } {
|
||||
const hasExecutorEstimate = typeof task.estimateHours === 'number' && task.estimateHours > 0;
|
||||
const hasAiEstimate = typeof task.aiEstimateHours === 'number' && task.aiEstimateHours > 0;
|
||||
const prefix = hasExecutorEstimate ? '执行预' : hasAiEstimate ? 'AI预' : '预';
|
||||
if (actual <= 0) return { text: `${prefix} ${formatWorkHours(estimate)}`, tone: 'text-[var(--ink-muted)]' };
|
||||
let tone = 'text-[var(--ink-soft)]';
|
||||
if (actual > estimate) tone = 'text-red-600';
|
||||
else if (actual < estimate) tone = 'text-emerald-600';
|
||||
@@ -46,7 +49,7 @@ export function DevTaskRow({ task, category, onClick }: Props) {
|
||||
const estimate = getEstimateHours(task);
|
||||
const actual = getActualHours(task);
|
||||
const range = timeRangeText(task);
|
||||
const hours = hoursText(estimate, actual);
|
||||
const hours = hoursText(task, estimate, actual);
|
||||
|
||||
return (
|
||||
<div
|
||||
|
||||
Reference in New Issue
Block a user