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.
77 lines
2.3 KiB
TypeScript
77 lines
2.3 KiB
TypeScript
"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}
|
||
/>
|
||
);
|
||
}
|