fOERbico/docs/report-content-statistik.html

210 lines
45 KiB
HTML
Raw Normal View History

2026-05-13 11:48:27 +02:00
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="utf-8">
<title>Inhalts-Statistik · oer.community</title>
<style>
body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
margin: 0; padding: 24px; background: #f5f6f8; color: #222; }
.wrap { max-width: 1400px; margin: 0 auto; background: #fff;
padding: 28px 32px; border-radius: 10px;
box-shadow: 0 2px 10px rgba(0,0,0,0.05); }
h1 { margin: 0 0 4px 0; font-size: 24px; }
.sub { color: #777; margin: 0 0 24px 0; font-size: 13px; }
.cards { display: grid; grid-template-columns: repeat(auto-fit,minmax(170px,1fr));
gap: 14px; margin-bottom: 28px; }
.card { background: linear-gradient(135deg,#5b6cff,#8a4cf0); color: #fff;
padding: 16px 18px; border-radius: 8px; }
.card h3 { margin: 0 0 6px 0; font-size: 12px; opacity: .85;
font-weight: 500; text-transform: uppercase; letter-spacing: .5px; }
.card .v { font-size: 26px; font-weight: 700; }
.controls { display: flex; gap: 12px; align-items: center;
margin-bottom: 14px; flex-wrap: wrap; }
.controls input { flex: 1; min-width: 240px; padding: 9px 12px;
font-size: 14px; border: 1px solid #ccc; border-radius: 6px; }
.controls .info { color: #666; font-size: 13px; }
table { width: 100%; border-collapse: collapse; font-size: 13px; }
thead th { background: #2d3142; color: #fff; font-weight: 600;
padding: 10px 8px; text-align: left; cursor: pointer;
user-select: none; position: sticky; top: 0; z-index: 1; }
thead th:hover { background: #3d4255; }
thead th.sort-asc::after { content: " ▲"; opacity: .7; }
thead th.sort-desc::after { content: " ▼"; opacity: .7; }
thead th.num { text-align: right; }
tbody td { padding: 7px 8px; border-bottom: 1px solid #eee; }
tbody tr:hover { background: #f8f9fa; }
td.path { font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
font-size: 12px; word-break: break-all; }
td.num { text-align: right; font-variant-numeric: tabular-nums; }
.pager { margin-top: 16px; display: flex; gap: 8px; align-items: center;
justify-content: center; }
.pager button { padding: 6px 12px; border: 1px solid #ccc; background: #fff;
border-radius: 4px; cursor: pointer; font-size: 13px; }
.pager button:disabled { opacity: .4; cursor: default; }
.pager .num { color: #666; font-size: 13px; padding: 0 8px; }
.footer { margin-top: 22px; color: #999; font-size: 12px; text-align: center; }
.hint { background: #fff8dc; border-left: 4px solid #f0c419;
padding: 10px 14px; margin-bottom: 22px; border-radius: 4px;
font-size: 13px; color: #6a5b00; }
a { color: #4a5cf0; text-decoration: none; }
a:hover { text-decoration: underline; }
</style>
</head>
<body>
<div class="wrap">
<h1>Inhalts-Statistik · oer.community</h1>
<p class="sub">Aufrufe pro Seite/Post · nur menschliche Besucher (Bots separat) · Quelle: Apache-Logs www + Apex</p>
<p class="sub"><strong>Indexierter Zeitraum:</strong> 14.07.2025 13.05.2026 (304 Tage) · generiert am 13.05.2026 12:27</p>
2026-05-13 11:48:27 +02:00
<div class="cards">
<div class="card"><h3>Inhalts-URLs</h3><div class="v">437</div></div>
<div class="card"><h3>Aufrufe (Mensch, total)</h3><div class="v">78,007</div></div>
<div class="card"><h3>Aufrufe (Bot)</h3><div class="v">82,983</div></div>
<div class="card"><h3>Aufrufe letzte 7 Tage</h3><div class="v">2,420</div></div>
<div class="card"><h3>Aufrufe letzte 30 Tage</h3><div class="v">8,959</div></div>
</div>
<div class="hint">
<strong>Bedienung:</strong> Spaltenüberschrift anklicken zum Sortieren · Suchfeld
filtert URLs (z.&nbsp;B. nach „junia“) · URL-Klick öffnet die Live-Seite.<br>
<strong>Filterung:</strong> Nur GET-Requests mit Status 2xx/304 auf
erkennbare Inhalts-URLs (keine Assets, keine Scanner-Pfade). Bots werden im
User-Agent erkannt und separat ausgewiesen.
</div>
<div class="controls">
<input type="search" id="q" placeholder="URLs durchsuchen…" autocomplete="off">
<span class="info" id="info"></span>
</div>
<div style="overflow-x:auto">
<table id="t">
<thead><tr>
<th data-col="0">URL</th>
<th data-col="1" class="num">Aufrufe gesamt</th>
2026-05-13 11:48:27 +02:00
<th data-col="2" class="num">Besucher (IPs)</th>
<th data-col="3" class="num">letzte 7 Tage</th>
<th data-col="4" class="num">letzte 30 Tage</th>
<th data-col="5" class="num">letzte 90 Tage</th>
<th data-col="6" class="num">davon Bots</th>
2026-05-13 11:48:27 +02:00
<th data-col="7">Erster Hit</th>
<th data-col="8">Letzter Hit</th>
</tr></thead>
<tbody id="tb"></tbody>
</table>
</div>
<div class="pager">
<button id="prev"> zurück</button>
<span class="num" id="page-info"></span>
<button id="next">weiter </button>
</div>
<div class="footer">
437 URLs · 78,007 menschliche Aufrufe ·
82,983 Bot-Aufrufe · CSV-Export: <code>report-content-statistik.csv</code>
</div>
</div>
<script>
const ROWS = [["/", 17295, 6586, 516, 1911, 5572, 7741, "2025-07-14", "2026-05-13"], ["/blog/", 2382, 1185, 73, 215, 525, 671, "2025-07-14", "2026-05-12"], ["/oer-und-oep/", 2079, 1271, 31, 270, 741, 836, "2025-07-14", "2026-05-13"], ["/canva/", 1916, 491, 62, 273, 824, 876, "2025-07-14", "2026-05-13"], ["/digitale-offenheit-braucht-tiefe/", 1600, 342, 57, 222, 681, 731, "2025-10-17", "2026-05-12"], ["/oer-beratung-und-qualitätskriterien/", 1573, 320, 59, 220, 693, 961, "2025-08-01", "2026-05-12"], ["/edufeed-pitch/", 1504, 258, 51, 217, 672, 895, "2025-10-01", "2026-05-12"], ["/unser-team/", 1421, 1045, 39, 152, 450, 668, "2025-07-14", "2026-05-13"], ["/instagram-als-lernort/", 1239, 650, 18, 40, 92, 689, "2025-07-31", "2026-05-13"], ["/luther-influencer/", 1159, 785, 18, 90, 237, 916, "2025-10-13", "2026-05-12"], ["/datenschutz/", 1056, 635, 28, 107, 299, 470, "2025-07-14", "2026-05-13"], ["/oer-oep-literaturbericht/", 976, 645, 12, 78, 274, 1505, "2025-08-06", "2026-05-12"], ["/save-the-date/", 965, 587, 13, 40, 112, 1071, "2025-07-23", "2026-05-13"], ["/impressum/", 891, 616, 22, 74, 234, 524, "2025-07-14", "2026-05-13"], ["/tagungen/", 873, 630, 20, 98, 399, 369, "2025-11-12", "2026-05-13"], ["/ist-die-bibel-eigentlich-open/", 779, 532, 14, 73, 273, 978, "2025-07-14", "2026-05-13"], ["/qualitaet/", 774, 566, 30, 115, 391, 465, "2025-12-23", "2026-05-13"], ["/wertebildung/", 727, 480, 8, 43, 134, 502, "2025-11-10", "2026-05-12"], ["/qualitaetskriterien-checkliste/", 677, 459, 14, 50, 185, 710, "2025-11-24", "2026-05-12"], ["/musik-oer/", 677, 390, 13, 79, 253, 1028, "2025-12-18", "2026-05-12"], ["/lichtmomente/", 666, 478, 22, 67, 173, 299, "2025-12-11", "2026-05-13"], ["/sdg-logos-und-oer-wie-darf-ich-sie-verwenden/", 663, 418, 17, 81, 191, 920, "2025-07-14", "2026-05-12"], ["/der-loewe-schwierigkeiten/", 641, 467, 15, 89, 318, 374, "2026-02-04", "2026-05-13"], ["/blog/seite/2/", 634, 352, 15, 49, 125, 233, "2025-07-14", "2026-05-12"], ["/going-deep-er-oerf-tagung-2025/", 601, 451, 15, 44, 142, 590, "2025-07-14", "2026-05-12"], ["/ki-und-religionspaedagogik/", 583, 463, 9, 39, 107, 744, "2025-08-14", "2026-05-12"], ["/recap-foerbico-tagung-2026/", 536, 390, 17, 173, 536, 461, "2026-03-25", "2026-05-12"], ["/oer-visuelle-qualität/", 515, 345, 9, 26, 76, 987, "2025-09-22", "2026-05-12"], ["/hackathoern/", 508, 247, 6, 33, 110, 462, "2025-07-14", "2026-05-13"], ["/theologie-memes/", 504, 337, 13, 50, 117, 875, "2025-10-06", "2026-05-11"], ["/tags/", 486, 388, 16, 57, 150, 488, "2025-07-14", "2026-05-13"], ["/sind-youtube-videos-oer-faehig/", 440, 342, 18, 45, 137, 678, "2025-07-14", "2026-05-13"], ["/oer-im-blick-2025/", 435, 235, 5, 32, 108, 463, "2025-07-14", "2026-05-13"], ["/oerinfo-fachtag-2025/", 429, 268, 6, 32, 110, 525, "2025-11-04", "2026-05-12"], ["/so-arbeiten-wir/", 418, 286, 6, 32, 108, 459, "2025-07-14", "2026-05-12"], ["/oercamp-und-oer-festival-2024-in-essen/", 410, 132, 20, 58, 117, 540, "2025-07-14", "2026-05-13"], ["/oer-fortbildungsreihe-3/", 408, 222, 9, 37, 107, 371, "2025-07-14", "2026-05-12"], ["/oer-und-oep/lernmodul/", 400, 256, 9, 49, 154, 188, "2026-01-13", "2026-05-13"], ["/oep-als-wissenstransfer/", 395, 144, 3, 29, 88, 453, "2025-07-14", "2026-05-13"], ["/oep-von-ressourcen-zu-praktiken/", 381, 237, 5, 17, 66, 791, "2025-09-11", "2026-05-12"], ["/triebfedoern/", 373, 251, 4, 21, 84, 751, "2025-07-15", "2026-05-13"], ["/oer-fortbildungsreihe-2/", 371, 210, 6, 27, 90, 370, "2025-07-14", "2026-05-12"], ["/markdown-einfuehrung-klimaoer/", 370, 168, 5, 26, 90, 449, "2025-07-14", "2026-05-12"], ["/oer-it-sommercamp-2025/", 364, 227, 6, 22, 66, 581, "2025-09-08", "2026-05-13"], ["/gemeinsam-gegen-antisemitismus/", 349, 160, 4, 32, 91, 352, "2025-07-14", "2026-05-13"], ["/theologie-auf-tiktok-religioese-kommunikation-im-digitalen-raum/", 348, 239, 16, 52, 126, 698, "2025-07-14", "2026-05-13"], ["/open-ist-eine-haltung/", 333, 239, 12, 32, 95, 555, "2025-12-12", "2026-05-12"], ["/oer-fortbildungsreihe-1/", 324, 173, 7, 24, 80, 375, "2025-07-14", "2026-05-12"], ["/en/", 321, 271, 21, 92, 237, 2
const SITE = "https://oer.community";
const PAGE_SIZE = 50;
let state = { filtered: [...ROWS], sortCol: 1, sortDir: -1, page: 0 };
const tb = document.getElementById("tb");
const info = document.getElementById("info");
const pageInfo = document.getElementById("page-info");
const q = document.getElementById("q");
const prev = document.getElementById("prev");
const next = document.getElementById("next");
const ths = document.querySelectorAll("thead th");
function escapeHtml(s) {
return String(s).replace(/[&<>"']/g, c => (
{ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#39;" })[c]);
}
function render() {
const start = state.page * PAGE_SIZE;
const end = Math.min(start + PAGE_SIZE, state.filtered.length);
const slice = state.filtered.slice(start, end);
tb.innerHTML = slice.map(r => {
const path = escapeHtml(r[0]);
return `<tr>
<td class="path"><a href="${SITE}${path}" target="_blank" rel="noopener">${path}</a></td>
<td class="num">${r[1].toLocaleString("de-DE")}</td>
<td class="num">${r[2].toLocaleString("de-DE")}</td>
<td class="num">${r[3].toLocaleString("de-DE")}</td>
<td class="num">${r[4].toLocaleString("de-DE")}</td>
<td class="num">${r[5].toLocaleString("de-DE")}</td>
<td class="num">${r[6].toLocaleString("de-DE")}</td>
<td>${escapeHtml(r[7])}</td>
<td>${escapeHtml(r[8])}</td>
</tr>`;
}).join("");
const total = state.filtered.length;
info.textContent = total === ROWS.length
? `${total} URLs`
: `${total} von ${ROWS.length} URLs (gefiltert)`;
pageInfo.textContent = total === 0
? "keine Treffer"
: `${start + 1}${end} von ${total}`;
prev.disabled = state.page === 0;
next.disabled = end >= total;
ths.forEach((th, i) => {
th.classList.remove("sort-asc", "sort-desc");
if (i === state.sortCol) {
th.classList.add(state.sortDir > 0 ? "sort-asc" : "sort-desc");
}
});
}
function sortRows() {
const c = state.sortCol;
const d = state.sortDir;
state.filtered.sort((a, b) => {
const av = a[c], bv = b[c];
if (typeof av === "number" && typeof bv === "number") return (av - bv) * d;
return String(av).localeCompare(String(bv), "de") * d;
});
}
function applyFilter() {
const term = q.value.toLowerCase().trim();
state.filtered = term
? ROWS.filter(r => r[0].toLowerCase().includes(term))
: [...ROWS];
sortRows();
state.page = 0;
render();
}
ths.forEach(th => {
th.addEventListener("click", () => {
const col = parseInt(th.dataset.col, 10);
if (state.sortCol === col) {
state.sortDir *= -1;
} else {
state.sortCol = col;
state.sortDir = (col >= 1 && col <= 6) ? -1 : 1;
}
sortRows();
state.page = 0;
render();
});
});
q.addEventListener("input", applyFilter);
prev.addEventListener("click", () => { state.page--; render(); });
next.addEventListener("click", () => { state.page++; render(); });
sortRows();
render();
</script>
</body>
</html>