diff --git a/backend/app/api/v1/parcels.py b/backend/app/api/v1/parcels.py index 6600a3ae..3cda9516 100644 --- a/backend/app/api/v1/parcels.py +++ b/backend/app/api/v1/parcels.py @@ -2966,8 +2966,9 @@ def analyze_parcel( "score_label": _score_label(score_final), "score_max_reference": SCORE_MAX_REFERENCE, "score_explanation": ( - "Сумма close-distance POI (школы/сады/парки +, трамваи -) + center_bonus. " - ">40 = редко, типичный город. центр 15-30." + "POI-скор (0–40, оценочный) — взвешенная сумма близких POI с учётом " + "расстояния + бонус за центр. Не инвест-рейтинг: школы/сады/парки " + "повышают, трамвайные пути снижают. Типичный город 15–30, >40 редко." ), "score_breakdown": by_category, # X1 (#47): per-factor контрибуции с verbal explain + top-3 / by-group. diff --git a/frontend/src/app/legacy/site-finder/page.tsx b/frontend/src/app/legacy/site-finder/page.tsx index dc2c7e57..76288bd4 100644 --- a/frontend/src/app/legacy/site-finder/page.tsx +++ b/frontend/src/app/legacy/site-finder/page.tsx @@ -245,8 +245,8 @@ function SiteFinderContent() { ? `${data.score.toFixed(2)} / ${scoreMax.toFixed(0)}` : "—"; const scoreLabel = data?.score_label - ? `Score · ${data.score_label}` - : "Score"; + ? `POI-скор · ${data.score_label} · оценочный` + : "POI-скор · оценочный"; const scoreCardColor: KpiColor = data ? scoreKpiColor(data.score, scoreMax) : "neutral"; diff --git a/frontend/src/app/page.tsx b/frontend/src/app/page.tsx index a2f43082..819992fc 100644 --- a/frontend/src/app/page.tsx +++ b/frontend/src/app/page.tsx @@ -74,9 +74,9 @@ const COMPARISON_ROWS: ComparisonRow[] = [ gendesign: "DOM.РФ + Objective, еженедельно", }, { - feature: "Инвест-балл участка и объяснение", + feature: "POI-скор участка и объяснение", nspd: null, - gendesign: "Score 0–100 с разбором факторов", + gendesign: "POI-скор 0–40 с разбором факторов", }, { feature: "Прогноз цены и горизонты выхода", diff --git a/frontend/src/components/site-finder/KpiCard.tsx b/frontend/src/components/site-finder/KpiCard.tsx index 1bbc3eb2..f49b5f06 100644 --- a/frontend/src/components/site-finder/KpiCard.tsx +++ b/frontend/src/components/site-finder/KpiCard.tsx @@ -22,9 +22,14 @@ interface Props { value: string; label: string; color?: KpiColor; + /** + * Опциональная подпись под значением (caption-токен 12/16, --fg-tertiary). + * Видимая (не hover) — для честных квалификаторов вроде «оценочный». + */ + caption?: string; } -export function KpiCard({ value, label, color = "neutral" }: Props) { +export function KpiCard({ value, label, color = "neutral", caption }: Props) { return (
{value}
+ {caption ? ( +
+ {caption} +
+ ) : null}
0 → недонасыщенность (повод строить) → success/green * deficit_index < 0 → затоварка (предложения > спроса) → warn/danger @@ -15,7 +19,6 @@ import { Badge } from "@/components/ui/Badge"; import type { DemandSupplyForecast } from "@/types/forecast"; import { - DEFICIT_BALANCE_EPS, deficitVariant, deficitWord, fmtNum, @@ -77,12 +80,6 @@ export function ForecastHorizonsBlock({ forecasts, targetHorizon }: Props) { Горизонт Индекс дефицита - - Мес. предложения - Прогноз спроса, квартир @@ -95,7 +92,6 @@ export function ForecastHorizonsBlock({ forecasts, targetHorizon }: Props) { {rows.map((f) => { const di = f.deficit_index; - const balanced = Math.abs(di) < DEFICIT_BALANCE_EPS; const isTarget = f.horizon_months === targetHorizon; return ( - - {balanced ? "—" : fmtNum(f.months_of_inventory, 1)} - {Math.round(f.projected_demand_units).toLocaleString("ru")} diff --git a/frontend/src/components/site-finder/analysis/Section1ParcelInfo.tsx b/frontend/src/components/site-finder/analysis/Section1ParcelInfo.tsx index a0c6c1b1..3a364e7d 100644 --- a/frontend/src/components/site-finder/analysis/Section1ParcelInfo.tsx +++ b/frontend/src/components/site-finder/analysis/Section1ParcelInfo.tsx @@ -202,13 +202,15 @@ export function Section1ParcelInfo({ cad }: Props) { : "—"; const scoreStr = `${data.score}`; - // Score color + // Score color — пороги выровнены под калиброванную 0–40 шкалу _score_label + // (#1871 P2: было 0–100, давало red на хорошем ~30/40 участке). + // <5 плохо · 5–15 средне · 15–25 хорошо · ≥25 отлично. const scoreColor = - data.score >= 80 + data.score >= 25 ? "green" - : data.score >= 65 + : data.score >= 15 ? "blue" - : data.score >= 45 + : data.score >= 5 ? "amber" : "red"; @@ -276,7 +278,12 @@ export function Section1ParcelInfo({ cad }: Props) { - +
{/* 2-column grid: map (left) + EGRN + POI (right) */} diff --git a/frontend/src/components/site-finder/compare/CompareTable.tsx b/frontend/src/components/site-finder/compare/CompareTable.tsx index 53d2c956..7916c0de 100644 --- a/frontend/src/components/site-finder/compare/CompareTable.tsx +++ b/frontend/src/components/site-finder/compare/CompareTable.tsx @@ -102,7 +102,7 @@ const METRIC_ROWS: MetricRow[] = [ }, { key: "score", - label: "Инвест-балл", + label: "POI-скор · 0–40", winner: "high", value: (c) => c.score ?? null, render: (c) => (