36 lines
1.2 KiB
TypeScript
36 lines
1.2 KiB
TypeScript
import { formatActualDuration } from './work-hours';
|
|
|
|
export interface EffortSummaryInput {
|
|
aiEstimateHours?: number;
|
|
estimateHours?: number;
|
|
actualHours: number;
|
|
manhours: number;
|
|
}
|
|
|
|
export interface EffortSummaryMetric {
|
|
label: 'AI预估' | '执行预估' | '实际耗时' | '人力投入';
|
|
value: string;
|
|
}
|
|
|
|
export function sumPositiveHours<T>(items: readonly T[], getValue: (item: T) => number | undefined): number | undefined {
|
|
let total = 0;
|
|
for (const item of items) {
|
|
const value = getValue(item);
|
|
if (typeof value === 'number' && value > 0) total += value;
|
|
}
|
|
return total > 0 ? Number(total.toFixed(2)) : undefined;
|
|
}
|
|
|
|
export function buildEffortSummaryMetrics(input: EffortSummaryInput): EffortSummaryMetric[] {
|
|
return [
|
|
{ label: 'AI预估', value: formatOptionalHours(input.aiEstimateHours) },
|
|
{ label: '执行预估', value: formatOptionalHours(input.estimateHours) },
|
|
{ label: '实际耗时', value: formatActualDuration(input.actualHours) },
|
|
{ label: '人力投入', value: formatActualDuration(input.manhours) },
|
|
];
|
|
}
|
|
|
|
function formatOptionalHours(hours?: number): string {
|
|
return typeof hours === 'number' && hours > 0 ? formatActualDuration(hours) : '-';
|
|
}
|