diff --git a/frontend/src/components/analytics/ObjectSaleChart.tsx b/frontend/src/components/analytics/ObjectSaleChart.tsx index 8c7d64a4..950e16cb 100644 --- a/frontend/src/components/analytics/ObjectSaleChart.tsx +++ b/frontend/src/components/analytics/ObjectSaleChart.tsx @@ -23,31 +23,34 @@ export function ObjectSaleChart({ objId }: { objId: number | string }) { yAxis: { show: false }, }; } + // Каждый тип (apartments / parking / nonliv) приходит от DOM.RF отдельным + // запросом со СВОИМ набором месяцев — они не обязаны совпадать (parking + // может стартовать позже). Строим ось X из union всех месяцев и маппим + // значения каждого типа по месяцу через Map (а не позиционно), чтобы бары + // и линия цены не «съезжали» на чужие месяцы и точки не обрезались молча. const byType: Record< string, { - months: string[]; - realised: number[]; - contracted: number[]; - price: (number | null)[]; + realised: Map; + price: Map; } > = {}; for (const p of points) { const t = p.type; - if (!byType[t]) - byType[t] = { months: [], realised: [], contracted: [], price: [] }; - byType[t].months.push((p.report_month ?? "").slice(0, 7)); - byType[t].realised.push(p.realised ?? 0); - byType[t].contracted.push(p.contracted ?? 0); - byType[t].price.push(p.price_avg); + if (!byType[t]) byType[t] = { realised: new Map(), price: new Map() }; + const m = (p.report_month ?? "").slice(0, 7); + byType[t].realised.set(m, p.realised ?? 0); + byType[t].price.set(m, p.price_avg); } - const months = Object.values(byType)[0]?.months ?? []; + const months = Array.from( + new Set(points.map((p) => (p.report_month ?? "").slice(0, 7))), + ).sort(); const series = Object.entries(byType).flatMap(([type, d]) => [ { name: `${type} · реализовано`, type: "bar", stack: type, - data: d.realised, + data: months.map((m) => d.realised.get(m) ?? null), itemStyle: { color: type === "apartments" ? "#1d4ed8" : "#9333ea" }, }, { @@ -56,7 +59,10 @@ export function ObjectSaleChart({ objId }: { objId: number | string }) { yAxisIndex: 1, smooth: true, symbol: "circle", - data: d.price.map((v) => (v ? Math.round(v) : null)), + data: months.map((m) => { + const v = d.price.get(m); + return v ? Math.round(v) : null; + }), lineStyle: { color: type === "apartments" ? "#0a7a3a" : "#c2410c" }, itemStyle: { color: type === "apartments" ? "#0a7a3a" : "#c2410c" }, connectNulls: true,