gendesign/frontend/src/components/site-finder/LandTab.tsx
lekss361 60d53bbf7d feat(site-finder): P2 cad_buildings соседи + overlap check (#46)
Backend (parcels.py):
- _parse_floors() helper для TEXT column (cad_buildings.floors хранится как
  строка, могут быть диапазоны "5-7"). Возвращает верхнюю границу.
- _neighbors_summary(db, geom_wkt, our_cad) — query соседей в 100м (GIST):
  cad_num, building_name, floors, year_built, cost_value, area, address, distance.
  Aggregate: avg_floors_100m, max_floors_100m, median_cost_per_m2_100m,
  count_buildings_100m. Outliers cost/m² фильтруются (1k < x < 500k).
- Overlap check: ST_Intersects + ST_Area(ST_Intersection) > 50 m² (transformed
  to UTM 32641 для метров). Если есть → has_existing_buildings: true +
  overlap_buildings list.
- В response → neighbors_summary.

Frontend:
- Новый NeighborsBlock.tsx: hard red warn block для overlap (с building names +
  overlap_m2 + "Инвестиции невозможны без сноса"); summary metrics (avg/max
  floors, median price); toggle "Показать N ближайших" → таблица.
- Border меняется на красный при has_existing_buildings — visual cue.
- Добавлен в LandTab выше "Зонирование (ПЗЗ)".
- TS типы: NeighborBuilding, OverlapBuilding, NeighborsSummary.

Closes #46. Closes #21 (cad_buildings в Site Finder фильтрах).
2026-05-12 01:12:29 +03:00

131 lines
3.6 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 type { ParcelAnalysis } from "@/types/site-finder";
import { GeologyBlock } from "./GeologyBlock";
import { GeotechRiskBlock } from "./GeotechRiskBlock";
import { NeighborsBlock } from "./NeighborsBlock";
interface Props {
data: ParcelAnalysis;
}
export function LandTab({ data }: Props) {
const hasAny =
data.geotech_risk !== undefined ||
data.geology !== undefined ||
data.neighbors_summary !== undefined;
return (
<div style={{ display: "flex", flexDirection: "column", gap: 20 }}>
{/* P2 (#46) — Соседи + overlap warning */}
{data.neighbors_summary && (
<NeighborsBlock data={data.neighbors_summary} />
)}
{/* Zoning note */}
<div
style={{
background: "#f9fafb",
border: "1px solid #e5e7eb",
borderRadius: 10,
padding: "14px 18px",
}}
>
<div
style={{
fontSize: 12,
fontWeight: 600,
color: "#6b7280",
textTransform: "uppercase",
letterSpacing: "0.05em",
marginBottom: 8,
}}
>
Зонирование (ПЗЗ)
</div>
<div style={{ fontSize: 13, color: "#6b7280" }}>
Данные ПЗЗ доступны через{" "}
<a
href="https://pkk.rosreestr.ru/"
target="_blank"
rel="noopener noreferrer"
style={{ color: "#1d4ed8", textDecoration: "none" }}
>
Публичную кадастровую карту
</a>
. API Росреестра закрыт в 2024 используйте deep-link для кад. номера{" "}
<strong style={{ color: "#374151" }}>{data.cad_num}</strong>.
</div>
<a
href={`https://pkk.rosreestr.ru/#/search/${encodeURIComponent(data.cad_num)}`}
target="_blank"
rel="noopener noreferrer"
style={{
display: "inline-block",
marginTop: 10,
padding: "6px 14px",
background: "#1d4ed8",
color: "#fff",
borderRadius: 6,
fontSize: 13,
fontWeight: 500,
textDecoration: "none",
}}
>
Открыть в ПКК
</a>
</div>
{/* Geotech risk */}
{data.geotech_risk !== undefined && (
<div>
<div
style={{
fontSize: 12,
fontWeight: 600,
color: "#6b7280",
textTransform: "uppercase",
letterSpacing: "0.05em",
marginBottom: 12,
}}
>
Геотехнический риск
</div>
<GeotechRiskBlock risk={data.geotech_risk} />
</div>
)}
{/* Geology */}
{data.geology !== undefined && (
<div>
<div
style={{
fontSize: 12,
fontWeight: 600,
color: "#6b7280",
textTransform: "uppercase",
letterSpacing: "0.05em",
marginBottom: 12,
}}
>
Геология
</div>
<GeologyBlock geology={data.geology} />
</div>
)}
{!hasAny && (
<div
style={{
fontSize: 13,
color: "#9ca3af",
padding: "24px 0",
textAlign: "center",
}}
>
Данные о земле и геологии недоступны
</div>
)}
</div>
);
}