panels-origin/web-panel/utils/workProgramGantt.ts
Cursor Agent 40703245af
feat: Gantt como vista principal del programa de obra
El Excel por partida no llena Conceptos (por eso se veían 0–0).
Gantt pasa a ser la primera pestaña, con barras de Sem primera a última
según erogaciones, y encabezado alineado por semana.

Co-authored-by: alberto.martinez <alberto.martinez@mrdev.mx>
2026-09-08 22:07:16 +00:00

37 lines
1.3 KiB
TypeScript

/** period_index is 1-based (Sem 1 … Sem N). */
export function ganttSpan(
activeIndexes: number[],
periodCount: number,
): { leftPct: number; widthPct: number; first: number; last: number } | null {
const n = Number(periodCount) || 0;
const idxs = activeIndexes.filter((i) => Number.isFinite(i) && i >= 1 && (n <= 0 || i <= n));
if (!idxs.length || n <= 0) return null;
const first = Math.min(...idxs);
const last = Math.max(...idxs);
return {
first,
last,
leftPct: ((first - 1) / n) * 100,
widthPct: ((last - first + 1) / n) * 100,
};
}
export function periodHasAmount(
periods: { period_id?: number; period_index?: number; amount?: number }[],
week: { id: number; period_index: number },
): number {
const slot = periods.find((x) => x.period_index === week.period_index || x.period_id === week.id);
return Number(slot?.amount || 0);
}
export function periodHasConceptBar(
periods: { period_index?: number; start_pct?: number; end_pct?: number }[],
week: { period_index: number },
): { start_pct: number; end_pct: number } | null {
const slot = periods.find((x) => x.period_index === week.period_index);
if (!slot) return null;
const start = Number(slot.start_pct || 0);
const end = Number(slot.end_pct || 0);
if (start === 0 && end === 0) return null;
return { start_pct: start, end_pct: Math.max(start, end) };
}