Backend (parcels.py): - _polygon_suitability() — Shapely metrics on parcel WGS84 polygon: area_ha/m2 (projected via cos(lat) к UTM-like meters), perimeter_m, aspect_ratio (long/short side of MABR), convex_hull_ratio (area / hull area), min_inscribed_rect_dim_m. - Composite suitability score 0..1: base = area_subscore (0 при <0.2 ha, linear → 1 при ≥0.5 ha) −0.3 если aspect_ratio > 5 (вытянутый) −0.3 если convex_hull_ratio < 0.65 (изрезанный) −0.5 если min_inscribed_rect_dim_m < 30 (узкий) - Label: микро / подходящий / сложная форма / слабо подходит - Recommendation: "для МКД 16+ нужно >0.3 ha + минимум 40м" - В analyze response → geometry_suitability. Frontend: - Новый GeometrySuitabilityBlock.tsx с color-coded badge + метрики grid + penalties + recommendation - Добавлен в LandTab (выше "Зонирование (ПЗЗ)") - TS типы расширены: GeometrySuitability Closes #45.
131 lines
3.6 KiB
TypeScript
131 lines
3.6 KiB
TypeScript
"use client";
|
||
|
||
import type { ParcelAnalysis } from "@/types/site-finder";
|
||
import { GeologyBlock } from "./GeologyBlock";
|
||
import { GeometrySuitabilityBlock } from "./GeometrySuitabilityBlock";
|
||
import { GeotechRiskBlock } from "./GeotechRiskBlock";
|
||
|
||
interface Props {
|
||
data: ParcelAnalysis;
|
||
}
|
||
|
||
export function LandTab({ data }: Props) {
|
||
const hasAny =
|
||
data.geotech_risk !== undefined ||
|
||
data.geology !== undefined ||
|
||
data.geometry_suitability !== undefined;
|
||
|
||
return (
|
||
<div style={{ display: "flex", flexDirection: "column", gap: 20 }}>
|
||
{/* P1 (#45) — Geometry suitability */}
|
||
{data.geometry_suitability !== undefined && (
|
||
<GeometrySuitabilityBlock data={data.geometry_suitability} />
|
||
)}
|
||
|
||
{/* 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>
|
||
);
|
||
}
|