|
|
@@ -189,12 +189,30 @@ foreach ($allTables as $t) {
|
|
|
if ($r && $r['ts']) $lastScrape = (string)$r['ts'];
|
|
|
}
|
|
|
|
|
|
+ // classification stats (only if column exists)
|
|
|
+ $classified = null;
|
|
|
+ $withPdf = null;
|
|
|
+ $typeBreakdown = [];
|
|
|
+ if (tableHasColumn($pdo, $t, 'application_type')) {
|
|
|
+ $row = $pdo->query("SELECT COUNT(local_document_url) AS with_pdf, COUNT(application_type) AS classified FROM `{$t}`")->fetch();
|
|
|
+ $withPdf = (int)$row['with_pdf'];
|
|
|
+ $classified = (int)$row['classified'];
|
|
|
+
|
|
|
+ $bt = $pdo->query("SELECT application_type, COUNT(*) AS n FROM `{$t}` WHERE application_type IS NOT NULL GROUP BY application_type ORDER BY n DESC");
|
|
|
+ while ($br = $bt->fetch()) {
|
|
|
+ $typeBreakdown[(string)$br['application_type']] = (int)$br['n'];
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
$summary[] = [
|
|
|
- 'council_key' => $t,
|
|
|
- 'council' => council_name_from_key($t),
|
|
|
- 'total' => $total,
|
|
|
- 'open' => $open,
|
|
|
- 'last_scrape' => $lastScrape,
|
|
|
+ 'council_key' => $t,
|
|
|
+ 'council' => council_name_from_key($t),
|
|
|
+ 'total' => $total,
|
|
|
+ 'open' => $open,
|
|
|
+ 'last_scrape' => $lastScrape,
|
|
|
+ 'classified' => $classified,
|
|
|
+ 'with_pdf' => $withPdf,
|
|
|
+ 'type_breakdown' => $typeBreakdown,
|
|
|
];
|
|
|
}
|
|
|
|
|
|
@@ -215,6 +233,11 @@ $cmp = function(array $a, array $b) use ($sort, $dir): int {
|
|
|
$bt = $b['last_scrape'] ? strtotime($b['last_scrape']) : 0;
|
|
|
return $mul * (($at <=> $bt) ?: strcasecmp($a['council'], $b['council']));
|
|
|
}
|
|
|
+ if ($sort === 'classified') {
|
|
|
+ $ac = ($a['with_pdf'] > 0) ? ($a['classified'] / $a['with_pdf']) : -1;
|
|
|
+ $bc = ($b['with_pdf'] > 0) ? ($b['classified'] / $b['with_pdf']) : -1;
|
|
|
+ return $mul * (($ac <=> $bc) ?: strcasecmp($a['council'], $b['council']));
|
|
|
+ }
|
|
|
|
|
|
return $mul * strcasecmp($a['council'], $b['council']);
|
|
|
};
|
|
|
@@ -232,6 +255,7 @@ usort($summary, $cmp);
|
|
|
body { padding: 24px; }
|
|
|
.muted { color:#6c757d; }
|
|
|
.nowrap { white-space: nowrap; }
|
|
|
+ .type-pill { display:inline-block; font-size:.7rem; padding:1px 6px; border-radius:10px; background:#e9ecef; color:#495057; margin:1px; white-space:nowrap; }
|
|
|
</style>
|
|
|
</head>
|
|
|
<body>
|
|
|
@@ -249,7 +273,8 @@ usort($summary, $cmp);
|
|
|
<option value="name" <?= $sort==='name'?'selected':'' ?>>sort: council</option>
|
|
|
<option value="last" <?= $sort==='last'?'selected':'' ?>>sort: last scrape</option>
|
|
|
<option value="count" <?= $sort==='count'?'selected':'' ?>>sort: total rows</option>
|
|
|
- <option value="open" <?= $sort==='open'?'selected':'' ?>>sort: open rows</option>
|
|
|
+ <option value="open" <?= $sort==='open'?'selected':'' ?>>sort: open rows</option>
|
|
|
+ <option value="classified" <?= $sort==='classified'?'selected':'' ?>>sort: classification %</option>
|
|
|
</select>
|
|
|
</div>
|
|
|
<div class="col-auto">
|
|
|
@@ -273,12 +298,13 @@ usort($summary, $cmp);
|
|
|
<table class="table table-sm table-bordered align-middle">
|
|
|
<thead class="table-light">
|
|
|
<tr>
|
|
|
- <th style="width: 24%">Council</th>
|
|
|
- <th style="width: 18%">Table</th>
|
|
|
- <th class="text-end" style="width: 12%">Total</th>
|
|
|
- <th class="text-end" style="width: 12%">Open</th>
|
|
|
- <th style="width: 22%">Last successful scrape</th>
|
|
|
- <th style="width: 12%"></th>
|
|
|
+ <th style="width: 18%">Council</th>
|
|
|
+ <th style="width: 14%">Table</th>
|
|
|
+ <th class="text-end" style="width: 8%">Total</th>
|
|
|
+ <th class="text-end" style="width: 8%">Open</th>
|
|
|
+ <th style="width: 18%">Last successful scrape</th>
|
|
|
+ <th style="width: 26%">Classification</th>
|
|
|
+ <th style="width: 8%"></th>
|
|
|
</tr>
|
|
|
</thead>
|
|
|
<tbody>
|
|
|
@@ -296,6 +322,27 @@ usort($summary, $cmp);
|
|
|
<span class="muted">unknown</span>
|
|
|
<?php endif; ?>
|
|
|
</td>
|
|
|
+ <td>
|
|
|
+ <?php if (is_null($r['classified'])): ?>
|
|
|
+ <span class="muted">—</span>
|
|
|
+ <?php elseif ($r['with_pdf'] === 0): ?>
|
|
|
+ <span class="muted">no PDFs</span>
|
|
|
+ <?php else:
|
|
|
+ $pct = (int)round(100 * $r['classified'] / $r['with_pdf']);
|
|
|
+ ?>
|
|
|
+ <div class="d-flex align-items-center gap-1 mb-1">
|
|
|
+ <div class="progress flex-grow-1" style="height:6px">
|
|
|
+ <div class="progress-bar" style="width:<?= $pct ?>%"></div>
|
|
|
+ </div>
|
|
|
+ <small class="muted nowrap"><?= $r['classified'] ?>/<?= $r['with_pdf'] ?></small>
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ <?php foreach ($r['type_breakdown'] as $type => $n): ?>
|
|
|
+ <span class="type-pill"><?= h($type) ?> <strong><?= $n ?></strong></span>
|
|
|
+ <?php endforeach; ?>
|
|
|
+ </div>
|
|
|
+ <?php endif; ?>
|
|
|
+ </td>
|
|
|
<td class="text-center">
|
|
|
<a class="btn btn-outline-secondary btn-sm"
|
|
|
href="index.php?council_key=<?= urlencode($r['council_key']) ?>">
|