gendesign/frontend/src/components/analytics/PrinzipDistrictsBar.tsx
lekss361 8d3a0874ef add interactive analytics dashboard for Sverdlovsk market and PRINZIP
3 pages (market, PRINZIP drilldown, developers leaderboard) on top of
existing v_developer_full_metrics + domrf_realization views. ECharts on
the frontend, FastAPI router /api/v1/analytics on the backend.
2026-04-27 16:55:30 +03:00

77 lines
2.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use client";
import { useMemo } from "react";
import { useDistricts, usePrinzipDistricts } from "@/lib/analytics-api";
import { ChartShell } from "./ChartShell";
export function PrinzipDistrictsBar() {
const districts = useDistricts();
const prinzip = usePrinzipDistricts();
const option = useMemo(() => {
const dRows = districts.data ?? [];
const pRows = prinzip.data ?? [];
const order = [...dRows]
.filter((r) => r.district_name !== "не определён")
.sort((a, b) => (b.zk_count ?? 0) - (a.zk_count ?? 0))
.map((r) => r.district_name);
return {
tooltip: {
trigger: "axis",
axisPointer: { type: "shadow" },
formatter: (
params: {
axisValueLabel: string;
marker: string;
seriesName: string;
value: number;
}[],
) => {
const district = params[0]?.axisValueLabel ?? "";
const total =
dRows.find((d) => d.district_name === district)?.zk_count ?? 0;
const prinzipRow = pRows.find((p) => p.district_name === district);
const share = prinzipRow?.share_in_district_pct ?? 0;
return [
`<b>${district}</b>`,
`Всего ЖК: ${total}`,
`PRINZIP: ${prinzipRow?.prinzip_zk ?? 0} (${share}%)`,
].join("<br/>");
},
},
legend: { data: ["Все девелоперы", "PRINZIP"] },
grid: { left: 120, right: 32, top: 40, bottom: 28 },
xAxis: { type: "value" },
yAxis: { type: "category", data: order, inverse: true },
series: [
{
name: "Все девелоперы",
type: "bar",
data: order.map(
(n) => dRows.find((d) => d.district_name === n)?.zk_count ?? 0,
),
itemStyle: { color: "#94a3b8" },
},
{
name: "PRINZIP",
type: "bar",
data: order.map(
(n) => pRows.find((p) => p.district_name === n)?.prinzip_zk ?? 0,
),
itemStyle: { color: "#1d4ed8" },
},
],
};
}, [districts.data, prinzip.data]);
return (
<ChartShell
option={option}
loading={districts.isLoading || prinzip.isLoading}
height={360}
/>
);
}