Заглушки навбара (href=#) → рабочие страницы. - GET /api/v1/trade-in/history — последние оценки из trade_in_estimates. - GET /api/v1/trade-in/cache-stats — счётчики данных/кэшей. - app/history/page.tsx — таблица прошлых оценок, ссылки на отчёты. - app/cache/page.tsx — состояние данных (объявления, сделки, кадастр, кэш геокодера, последний парсинг). - navbar — ссылки История / Кэш ведут на страницы. Closes #399
92 lines
2.9 KiB
TypeScript
92 lines
2.9 KiB
TypeScript
"use client";
|
||
|
||
/* Состояние данных и кэшей (#399). */
|
||
import { useEffect, useState } from "react";
|
||
|
||
import "@/components/trade-in/trade-in.css";
|
||
import { API_BASE_URL } from "@/lib/api";
|
||
|
||
interface CacheStats {
|
||
geocode_cache: number;
|
||
geocode_cache_fresh: number;
|
||
listings_active: number;
|
||
listings_last_scraped: string | null;
|
||
deals: number;
|
||
cad_buildings: number;
|
||
house_metadata: number;
|
||
estimates_total: number;
|
||
}
|
||
|
||
export default function CachePage() {
|
||
const [stats, setStats] = useState<CacheStats | null>(null);
|
||
const [loading, setLoading] = useState(true);
|
||
|
||
useEffect(() => {
|
||
fetch(`${API_BASE_URL}/api/v1/trade-in/cache-stats`)
|
||
.then((r) => (r.ok ? r.json() : null))
|
||
.then((d) => setStats(d as CacheStats | null))
|
||
.catch(() => setStats(null))
|
||
.finally(() => setLoading(false));
|
||
}, []);
|
||
|
||
const items: Array<[string, string]> = stats
|
||
? [
|
||
["Оценок всего", String(stats.estimates_total)],
|
||
["Объявлений активных", String(stats.listings_active)],
|
||
["Сделок", String(stats.deals)],
|
||
["Кадастр зданий", String(stats.cad_buildings)],
|
||
["Кэш домов (house_metadata)", String(stats.house_metadata)],
|
||
[
|
||
"Кэш геокодера (всего / свежих)",
|
||
`${stats.geocode_cache} / ${stats.geocode_cache_fresh}`,
|
||
],
|
||
[
|
||
"Последний парсинг объявлений",
|
||
stats.listings_last_scraped
|
||
? new Date(stats.listings_last_scraped).toLocaleString("ru-RU")
|
||
: "—",
|
||
],
|
||
]
|
||
: [];
|
||
|
||
return (
|
||
<main className="page" style={{ padding: 24, maxWidth: 700, margin: "0 auto" }}>
|
||
<p style={{ marginBottom: 12 }}>
|
||
<a href={`${API_BASE_URL}/`}>← К оценке</a>
|
||
</p>
|
||
<h1 style={{ fontSize: 20, fontWeight: 700, marginBottom: 16 }}>
|
||
Состояние данных и кэшей
|
||
</h1>
|
||
|
||
{loading ? (
|
||
<p style={{ color: "var(--muted)" }}>Загрузка…</p>
|
||
) : !stats ? (
|
||
<p style={{ color: "var(--muted)" }}>Не удалось загрузить статистику.</p>
|
||
) : (
|
||
<div
|
||
style={{
|
||
border: "1px solid var(--border, #e5e5e5)",
|
||
borderRadius: 8,
|
||
overflow: "hidden",
|
||
}}
|
||
>
|
||
{items.map(([k, v], i) => (
|
||
<div
|
||
key={k}
|
||
style={{
|
||
display: "flex",
|
||
justifyContent: "space-between",
|
||
padding: "11px 14px",
|
||
fontSize: 14,
|
||
borderTop: i === 0 ? "none" : "1px solid var(--border, #eee)",
|
||
}}
|
||
>
|
||
<span style={{ color: "var(--muted)" }}>{k}</span>
|
||
<span style={{ fontWeight: 600 }}>{v}</span>
|
||
</div>
|
||
))}
|
||
</div>
|
||
)}
|
||
</main>
|
||
);
|
||
}
|