From be5771931ebd4aa3839f21a765791c20dcb0acd7 Mon Sep 17 00:00:00 2001 From: bot-backend Date: Sun, 2 Aug 2026 19:01:59 +0300 Subject: [PATCH] =?UTF-8?q?feat(tradein/v2):=20=D0=BF=D0=BE=D0=BA=D0=B0?= =?UTF-8?q?=D0=B7=D0=B0=D1=82=D1=8C=20=D1=81=D1=80=D0=BE=D0=BA=20=D1=8D?= =?UTF-8?q?=D0=BA=D1=81=D0=BF=D0=BE=D0=B7=D0=B8=D1=86=D0=B8=D0=B8=20=D0=B2?= =?UTF-8?q?=20=D0=BA=D0=B0=D1=80=D1=82=D0=BE=D1=87=D0=BA=D0=B5=20=C2=AB?= =?UTF-8?q?=D0=BE=D0=B6=D0=B8=D0=B4=D0=B0=D0=B5=D0=BC=D0=B0=D1=8F=20=D1=86?= =?UTF-8?q?=D0=B5=D0=BD=D0=B0=20=D1=81=D0=B4=D0=B5=D0=BB=D0=BA=D0=B8=C2=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Подстрока «срок продажи ~N дн» под пилюлей дельты во второй карточке 02-РЕЗУЛЬТАТ, источник — analytics.kpi.median_exposure_days (реальные данные house_placement_history). Не используем est_days_on_market — считается по deals.days_on_market, который 0 в 96974/96974 строк. --- tradein-mvp/frontend/src/app/v2/page.tsx | 5 +++-- .../src/components/trade-in/v2/ResultPanel.tsx | 15 +++++++++++++++ .../src/components/trade-in/v2/mappers.ts | 8 ++++++++ .../frontend/src/components/trade-in/v2/types.ts | 2 ++ 4 files changed, 28 insertions(+), 2 deletions(-) diff --git a/tradein-mvp/frontend/src/app/v2/page.tsx b/tradein-mvp/frontend/src/app/v2/page.tsx index 813ed0c0..e398c129 100644 --- a/tradein-mvp/frontend/src/app/v2/page.tsx +++ b/tradein-mvp/frontend/src/app/v2/page.tsx @@ -599,8 +599,9 @@ export default function TradeInV2Page() { [locationIndexData], ); const resultPanelData = useMemo( - () => (estimate ? mapResultPanel(estimate, streetDealsData) : null), - [estimate, streetDealsData], + () => + estimate ? mapResultPanel(estimate, streetDealsData, analyticsData) : null, + [estimate, streetDealsData, analyticsData], ); const summaryData = useMemo( () => diff --git a/tradein-mvp/frontend/src/components/trade-in/v2/ResultPanel.tsx b/tradein-mvp/frontend/src/components/trade-in/v2/ResultPanel.tsx index 088fc12a..6bb5bc15 100644 --- a/tradein-mvp/frontend/src/components/trade-in/v2/ResultPanel.tsx +++ b/tradein-mvp/frontend/src/components/trade-in/v2/ResultPanel.tsx @@ -484,6 +484,7 @@ export default function ResultPanel({ // M2 — calm delta pill (was a 51px circular gauge that read like a // tech "занижение" indicator). Full text «−18% к цене объявления», // neutral accentDeep on a soft-blue chip, tabular-nums. + <>
+ {card.exposureNote && ( +
+ {card.exposureNote} +
+ )} + )} ); diff --git a/tradein-mvp/frontend/src/components/trade-in/v2/mappers.ts b/tradein-mvp/frontend/src/components/trade-in/v2/mappers.ts index 3c965409..79fd9f1e 100644 --- a/tradein-mvp/frontend/src/components/trade-in/v2/mappers.ts +++ b/tradein-mvp/frontend/src/components/trade-in/v2/mappers.ts @@ -1038,6 +1038,7 @@ export function mapMarkers(e: AggregatedEstimate | null): MapMarker[] { export function mapResultPanel( e: AggregatedEstimate, streetDeals?: StreetDealsResponse | null, + analytics?: HouseAnalyticsResponse | null, ): ResultPanelData { const dealTier = resolveDealTier(e, streetDeals); @@ -1105,6 +1106,13 @@ export function mapResultPanel( emptyNote: hasExpected ? undefined : "Недостаточно данных для прогноза цены сделки — ориентируйтесь на рекомендованную цену в объявлении", + // Median exposure days (house/district), from house_placement_history — + // gated on hasExpected: when the card has no forecast it renders only + // emptyNote (see above), the exposure aside has nowhere honest to sit. + exposureNote: + hasExpected && analytics?.kpi?.median_exposure_days != null + ? `срок продажи ~${analytics.kpi.median_exposure_days} дн` + : undefined, note: hasExpected && dealTier != null && diff --git a/tradein-mvp/frontend/src/components/trade-in/v2/types.ts b/tradein-mvp/frontend/src/components/trade-in/v2/types.ts index 32021e07..81ca7422 100644 --- a/tradein-mvp/frontend/src/components/trade-in/v2/types.ts +++ b/tradein-mvp/frontend/src/components/trade-in/v2/types.ts @@ -55,6 +55,8 @@ export interface ResultCard { deltaLabel?: string; /** Reconciliation note under the value (card 2: expected price vs ДКП median). */ note?: string; + /** Медиана срока экспозиции по дому/району (house_placement_history), подстрока карточки 2. */ + exposureNote?: string; /** H1 empty-state message: when set (card 2, no expected-sold prediction) the * card renders this instead of value/range/ppm/delta, and the panel moves the * accent frame onto the «рекомендованная цена» card. */