feat(tradein): tier badge на DealsCard rows (PR M follow-up #564)

PR M (#600) добавил confidence tier field в backend AnalogLot.actual_deals.
Этот PR показывает его UI:

- types/trade-in.ts: AnalogLot.tier?: string (T0_per_house / T1_per_street)
- DealsCard.tsx: DealRow рендерит badge рядом с источником
  * T0 «по дому» — var(--success) (кадастровый match)
  * T1 «по улице» — var(--fg-tertiary) (street-level default)
- trade-in.css: .tier-badge + .tier-t0 + .tier-t1 (token-only)

Current state: все rosreestr deals = T1 (open dataset не имеет kadastr_num).
Когда появится ЕГРН direct feed — высветятся T0.

Tests: tsc --noEmit clean.

Refs #564.
This commit is contained in:
Light1YT 2026-05-27 18:15:32 +05:00
parent 99a5a0f73b
commit 5a3e820f53
3 changed files with 40 additions and 0 deletions

View file

@ -149,6 +149,14 @@ function DealRow({ deal }: { deal: AnalogLot }) {
const dot = SOURCE_DOTS[src] ?? "dom";
const label = SOURCE_LABELS[src] ?? src;
// Tier badge для rosreestr deals (PR M / #564 Phase 3).
// T0_per_house — точный кадастровый match (high confidence).
// T1_per_street — улица-уровень (open dataset default).
const tierBadge =
deal.tier === "T0_per_house" ? { text: "по дому", className: "tier-badge tier-t0" }
: deal.tier === "T1_per_street" ? { text: "по улице", className: "tier-badge tier-t1" }
: null;
return (
<tr>
<td>
@ -166,6 +174,11 @@ function DealRow({ deal }: { deal: AnalogLot }) {
<span className="src-mini">
<span className={`src-dot ${dot}`} /> {label}
</span>
{tierBadge ? (
<span className={tierBadge.className} title="Точность сопоставления сделки">
{tierBadge.text}
</span>
) : null}
</td>
<td className="num">{fmtRub(deal.price_per_m2)}</td>
<td className="num">{fmtRub(deal.price_rub)}</td>

View file

@ -1691,3 +1691,26 @@
.listing-cell { min-width: 0; max-width: none; }
.listing-link { flex-direction: column; align-items: flex-start; gap: 2px; }
}
/* ── PR M (#564 Phase 3) — Tier badge for rosreestr deals ────────────────── */
.tier-badge {
display: inline-block;
margin-left: 6px;
padding: 1px 6px;
border-radius: 4px;
font-size: 10px;
font-weight: 600;
letter-spacing: 0.04em;
text-transform: uppercase;
vertical-align: middle;
}
.tier-t0 {
/* T0_per_house — точный кадастровый match (high confidence) */
background: var(--success-soft);
color: var(--success);
}
.tier-t1 {
/* T1_per_street — улица-уровень (open dataset default) */
background: var(--bg-card-alt);
color: var(--fg-tertiary);
}

View file

@ -44,6 +44,10 @@ export interface AnalogLot {
source: string | null; // 'avito' / 'cian' / 'domklik' / 'rosreestr'
source_url: string | null; // ссылка на оригинал
distance_m: number | null; // расстояние до целевой квартиры в метрах
// ── PR M (#564 Phase 3) — confidence tier для rosreestr deals ──
// 'T0_per_house' — kadastr_num exact match (currently not available in open dataset)
// 'T1_per_street' — street-level only (default for all rosreestr deals)
tier?: string | null;
}
export interface CianValuationSummary {