feat: add tab with all domain records
This commit is contained in:
parent
a98291316e
commit
6b5d385463
44
api.php
44
api.php
@ -230,6 +230,50 @@ if ($action === 'live_prices') {
|
||||
exit;
|
||||
}
|
||||
|
||||
if ($action === 'all_domains') {
|
||||
$q = trim($_GET['q'] ?? '');
|
||||
$tld = trim($_GET['tld'] ?? '');
|
||||
$limit = intval($_GET['limit'] ?? 2000);
|
||||
if ($limit < 1) $limit = 1;
|
||||
if ($limit > 5000) $limit = 5000;
|
||||
|
||||
$sql = "SELECT d.run_id, d.scanned_at, d.domain, d.tld, d.score, d.status, d.keywords_json,
|
||||
ls.llm_score, ls.decision, ls.reason
|
||||
FROM domains d
|
||||
LEFT JOIN llm_scores ls ON ls.run_id = d.run_id AND ls.domain = d.domain
|
||||
WHERE 1=1";
|
||||
|
||||
if ($q !== '') $sql .= " AND d.domain LIKE :q";
|
||||
if ($tld !== '') $sql .= " AND d.tld = :tld";
|
||||
|
||||
$sql .= " ORDER BY d.scanned_at DESC, d.score DESC, d.domain ASC LIMIT :limit";
|
||||
|
||||
$st = $db->prepare($sql);
|
||||
if ($q !== '') $st->bindValue(':q', '%' . $q . '%', SQLITE3_TEXT);
|
||||
if ($tld !== '') $st->bindValue(':tld', $tld, SQLITE3_TEXT);
|
||||
$st->bindValue(':limit', $limit, SQLITE3_INTEGER);
|
||||
|
||||
$res = $st->execute();
|
||||
$rows = [];
|
||||
while ($r = $res->fetchArray(SQLITE3_ASSOC)) {
|
||||
$r['keywords'] = json_decode($r['keywords_json'] ?: '[]', true) ?: [];
|
||||
$r['is_new'] = false;
|
||||
unset($r['keywords_json']);
|
||||
$rows[] = $r;
|
||||
}
|
||||
|
||||
echo json_encode([
|
||||
'ok' => true,
|
||||
'meta' => [
|
||||
'mode' => 'all',
|
||||
'count' => count($rows),
|
||||
'limit' => $limit,
|
||||
],
|
||||
'domains' => $rows,
|
||||
], JSON_UNESCAPED_UNICODE);
|
||||
exit;
|
||||
}
|
||||
|
||||
if ($action === 'prices') {
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$raw = json_decode(file_get_contents('php://input'), true) ?: [];
|
||||
|
||||
39
index.html
39
index.html
@ -24,6 +24,9 @@
|
||||
.pill input{width:78px;padding:4px 6px}
|
||||
.ok{color:#63db8f}.bad{color:#ff8b8b}
|
||||
.chip{display:inline-block;padding:2px 8px;border-radius:999px;font-size:11px;background:#264a32;color:#9df5bc;border:1px solid #3f8b5b}
|
||||
.tabbar{display:flex;gap:8px;flex-wrap:wrap;margin:8px 0 0}
|
||||
.tabbtn{cursor:pointer}
|
||||
.tabbtn.active{background:#2a3f86;border-color:#6e8cff;color:#fff}
|
||||
.small{font-size:12px}
|
||||
@media (max-width: 980px){.grid{grid-template-columns:1fr}}
|
||||
@media (max-width: 700px){
|
||||
@ -41,6 +44,10 @@
|
||||
|
||||
<div class="card">
|
||||
<h2>Filtr domen</h2>
|
||||
<div class="tabbar">
|
||||
<button id="tabCurrent" class="tabbtn active">Bieżący skan</button>
|
||||
<button id="tabAll" class="tabbtn">Wszystkie rekordy</button>
|
||||
</div>
|
||||
<div class="controls">
|
||||
<label>Szukaj <input id="q" placeholder="np. lead, ai, crm" /></label>
|
||||
<label>TLD
|
||||
@ -57,7 +64,7 @@
|
||||
<h2>TOP domen + porównanie cen (rejestracja / odnowienie)</h2>
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<thead><tr><th>Domena</th><th>TLD</th><th>Score</th><th>LLM</th><th>Status</th><th>Oferty (top 3)</th></tr></thead>
|
||||
<thead><tr><th>Domena</th><th>TLD</th><th>Score</th><th>LLM</th><th>Status</th><th>Run</th><th>Skan</th><th>Oferty (top 3)</th></tr></thead>
|
||||
<tbody id="rows"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
@ -67,6 +74,7 @@
|
||||
<script>
|
||||
let domains = [];
|
||||
let livePriceByTld = {};
|
||||
let viewMode = 'current';
|
||||
|
||||
function money(v){ return (v===null || v===undefined || Number.isNaN(Number(v))) ? '—' : `${Number(v).toFixed(2)} zł`; }
|
||||
|
||||
@ -126,13 +134,22 @@ async function loadDomains(){
|
||||
const tld = document.getElementById('tld').value;
|
||||
const onlyNew = document.getElementById('onlyNew').checked;
|
||||
const u = new URL('./api.php', location.href);
|
||||
u.searchParams.set('action','domains');
|
||||
if(viewMode === 'all'){
|
||||
u.searchParams.set('action','all_domains');
|
||||
u.searchParams.set('limit','2000');
|
||||
} else {
|
||||
u.searchParams.set('action','domains');
|
||||
if(onlyNew) u.searchParams.set('only_new', '1');
|
||||
}
|
||||
if(q) u.searchParams.set('q', q);
|
||||
if(tld) u.searchParams.set('tld', tld);
|
||||
if(onlyNew) u.searchParams.set('only_new', '1');
|
||||
const d = await (await fetch(u)).json();
|
||||
domains = d.domains || [];
|
||||
document.getElementById('meta').textContent = `runId: ${d.meta?.runId||'—'} | prev: ${d.meta?.prevRunId||'—'} | scannedAt: ${d.meta?.scannedAt||'—'} | nowe: ${d.meta?.newCount||0} | widoczne: ${domains.length}`;
|
||||
if(viewMode === 'all'){
|
||||
document.getElementById('meta').textContent = `widok: wszystkie rekordy | limit: ${d.meta?.limit||'—'} | widoczne: ${domains.length}`;
|
||||
} else {
|
||||
document.getElementById('meta').textContent = `runId: ${d.meta?.runId||'—'} | prev: ${d.meta?.prevRunId||'—'} | scannedAt: ${d.meta?.scannedAt||'—'} | nowe: ${d.meta?.newCount||0} | widoczne: ${domains.length}`;
|
||||
}
|
||||
}
|
||||
|
||||
function renderRows(){
|
||||
@ -159,6 +176,8 @@ function renderRows(){
|
||||
<td>${d.score}</td>
|
||||
<td>${llm}</td>
|
||||
<td>${d.status || 'available'}</td>
|
||||
<td class='small muted'>${d.run_id || '—'}</td>
|
||||
<td class='small muted'>${d.scanned_at || '—'}</td>
|
||||
<td>${offersHtml}</td>`;
|
||||
rows.appendChild(tr);
|
||||
}
|
||||
@ -185,6 +204,18 @@ function setupAutoRefresh(){
|
||||
}
|
||||
}
|
||||
|
||||
function setTab(mode){
|
||||
viewMode = mode;
|
||||
const currentBtn = document.getElementById('tabCurrent');
|
||||
const allBtn = document.getElementById('tabAll');
|
||||
currentBtn.classList.toggle('active', mode === 'current');
|
||||
allBtn.classList.toggle('active', mode === 'all');
|
||||
document.getElementById('onlyNew').disabled = (mode === 'all');
|
||||
refreshAll();
|
||||
}
|
||||
|
||||
document.getElementById('tabCurrent').addEventListener('click', ()=>setTab('current'));
|
||||
document.getElementById('tabAll').addEventListener('click', ()=>setTab('all'));
|
||||
document.getElementById('reload').addEventListener('click', refreshAll);
|
||||
document.getElementById('q').addEventListener('input', async()=>{
|
||||
clearTimeout(qTimer);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user