feat(ai): 优化拆解重跑与结果展示

This commit is contained in:
Script Generator
2026-06-26 11:01:11 +08:00
parent 55e24442ab
commit 56e0fe562d
36 changed files with 1342 additions and 186 deletions

View File

@@ -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>

View File

@@ -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>

View File

@@ -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