Admin: Social-Media-Tab mit Manager-Übersicht, Plattform-Auswertung und Post-Nachweis, SW by-v370
This commit is contained in:
parent
e2bb1a4b2d
commit
4f58a784c7
3 changed files with 182 additions and 1 deletions
|
|
@ -14,6 +14,7 @@ window.Page_admin = (() => {
|
|||
{ id: 'nutzer', label: 'Nutzer', icon: 'users' },
|
||||
{ id: 'moderation', label: 'Moderation', icon: 'shield-check' },
|
||||
{ id: 'forum', label: 'Forum & Meldungen', icon: 'chat-circle-dots' },
|
||||
{ id: 'social', label: 'Social Media', icon: 'camera' },
|
||||
{ id: 'analytics', label: 'Analytics', icon: 'target' },
|
||||
{ id: 'system', label: 'System', icon: 'gear' },
|
||||
{ id: 'jobs', label: 'Jobs', icon: 'clock' },
|
||||
|
|
@ -81,6 +82,7 @@ window.Page_admin = (() => {
|
|||
case 'nutzer': await _renderUsers(el); break;
|
||||
case 'moderation': await _renderModeration(el); break;
|
||||
case 'forum': await _renderForum(el); break;
|
||||
case 'social': await _renderSocial(el); break;
|
||||
case 'analytics': await _renderAnalytics(el); break;
|
||||
case 'system': await _renderSystem(el); break;
|
||||
case 'jobs': await _renderJobs(el); break;
|
||||
|
|
@ -91,6 +93,126 @@ window.Page_admin = (() => {
|
|||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// TAB: SOCIAL MEDIA
|
||||
async function _renderSocial(el) {
|
||||
const d = await API.get('/admin/social');
|
||||
|
||||
const _PL = { instagram: '📸 Instagram', tiktok: '🎵 TikTok', both: '📱 Beide' };
|
||||
const _fmt = iso => iso ? new Date(iso).toLocaleDateString('de-DE', {day:'2-digit',month:'2-digit',year:'numeric'}) : '–';
|
||||
|
||||
// Manager-Tabelle
|
||||
const managerRows = d.managers.map(m => `
|
||||
<tr>
|
||||
<td style="font-weight:600">${_esc(m.name)}</td>
|
||||
<td style="text-align:right">${m.published}</td>
|
||||
<td style="text-align:right">${m.with_link}
|
||||
${m.published > 0 ? `<span style="font-size:10px;color:var(--c-text-muted)">
|
||||
(${Math.round(m.with_link/m.published*100)}%)</span>` : ''}</td>
|
||||
<td style="text-align:right">${m.scheduled}</td>
|
||||
<td style="text-align:right">${m.ideas}</td>
|
||||
<td style="text-align:right;color:var(--c-text-muted)">${m.total}</td>
|
||||
</tr>`).join('');
|
||||
|
||||
// Plattform-Balken
|
||||
const maxPlat = Math.max(...d.by_platform.map(p => p.n), 1);
|
||||
const platBars = d.by_platform.map(p => `
|
||||
<div style="display:flex;align-items:center;gap:var(--space-3);margin-bottom:var(--space-2)">
|
||||
<div style="width:120px;flex-shrink:0;font-size:var(--text-sm)">${_PL[p.platform]||p.platform}</div>
|
||||
<div style="flex:1;background:var(--c-surface-2);border-radius:var(--radius-full);height:8px;overflow:hidden">
|
||||
<div style="width:${Math.round(p.n/maxPlat*100)}%;height:100%;
|
||||
background:var(--c-primary);border-radius:var(--radius-full)"></div>
|
||||
</div>
|
||||
<div style="width:28px;text-align:right;font-weight:600;font-size:var(--text-sm)">${p.n}</div>
|
||||
</div>`).join('');
|
||||
|
||||
// Monats-Timeline
|
||||
const maxMonth = Math.max(...d.by_month.map(m => m.n), 1);
|
||||
const monthBars = [...d.by_month].reverse().map(m => `
|
||||
<div style="display:flex;align-items:center;gap:var(--space-3);margin-bottom:var(--space-2)">
|
||||
<div style="width:55px;flex-shrink:0;font-size:11px;color:var(--c-text-muted)">${m.monat}</div>
|
||||
<div style="flex:1;background:var(--c-surface-2);border-radius:var(--radius-full);height:8px;overflow:hidden">
|
||||
<div style="width:${Math.round(m.n/maxMonth*100)}%;height:100%;
|
||||
background:var(--c-success);border-radius:var(--radius-full)"></div>
|
||||
</div>
|
||||
<div style="width:28px;text-align:right;font-weight:600;font-size:var(--text-sm)">${m.n}</div>
|
||||
</div>`).join('');
|
||||
|
||||
// Veröffentlichte Posts (mit/ohne Link)
|
||||
const postRows = d.recent_published.map(p => `
|
||||
<tr>
|
||||
<td style="color:var(--c-text-muted);white-space:nowrap">${_fmt(p.published_at)}</td>
|
||||
<td style="font-weight:500;max-width:200px;overflow:hidden;text-overflow:ellipsis;
|
||||
white-space:nowrap">${_esc(p.topic)}</td>
|
||||
<td>${_PL[p.platform]||p.platform||'–'}</td>
|
||||
<td style="font-size:10px;color:var(--c-text-muted)">${_esc(p.category||'–')}</td>
|
||||
<td>${p.ai_score ? '⭐'.repeat(p.ai_score) : '–'}</td>
|
||||
<td style="font-weight:500">${_esc(p.manager||'–')}</td>
|
||||
<td>${p.post_url
|
||||
? `<a href="${_esc(p.post_url)}" target="_blank" rel="noopener"
|
||||
style="font-size:11px;color:var(--c-primary)">🔗 Link</a>`
|
||||
: `<span style="font-size:11px;color:var(--c-text-muted)">–</span>`}</td>
|
||||
</tr>`).join('');
|
||||
|
||||
el.innerHTML = `
|
||||
<div style="display:grid;grid-template-columns:1fr 1fr;gap:var(--space-4);margin-bottom:var(--space-4)">
|
||||
<!-- Plattform -->
|
||||
<div class="card" style="padding:var(--space-4)">
|
||||
<div style="font-size:var(--text-sm);font-weight:700;margin-bottom:var(--space-3)">
|
||||
Veröffentlicht nach Plattform
|
||||
</div>
|
||||
${platBars || '<div style="color:var(--c-text-muted);font-size:var(--text-sm)">Noch keine Posts</div>'}
|
||||
</div>
|
||||
<!-- Timeline -->
|
||||
<div class="card" style="padding:var(--space-4)">
|
||||
<div style="font-size:var(--text-sm);font-weight:700;margin-bottom:var(--space-3)">
|
||||
Posts pro Monat
|
||||
</div>
|
||||
${monthBars || '<div style="color:var(--c-text-muted);font-size:var(--text-sm)">Noch keine Posts</div>'}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Manager -->
|
||||
${d.managers.length ? `
|
||||
<div class="card adm-table-card" style="margin-bottom:var(--space-4)">
|
||||
<div style="padding:var(--space-3) var(--space-4);font-size:var(--text-xs);font-weight:700;
|
||||
text-transform:uppercase;letter-spacing:.05em;color:var(--c-text-secondary);
|
||||
border-bottom:1px solid var(--c-border)">Manager-Übersicht</div>
|
||||
<div class="adm-table-scroll">
|
||||
<table class="adm-table">
|
||||
<thead><tr>
|
||||
<th>Manager</th>
|
||||
<th style="text-align:right">Veröffentlicht</th>
|
||||
<th style="text-align:right">Mit Link</th>
|
||||
<th style="text-align:right">Geplant</th>
|
||||
<th style="text-align:right">Ideen</th>
|
||||
<th style="text-align:right">Gesamt</th>
|
||||
</tr></thead>
|
||||
<tbody>${managerRows}</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>` : ''}
|
||||
|
||||
<!-- Alle veröffentlichten Posts -->
|
||||
<div class="card adm-table-card">
|
||||
<div style="padding:var(--space-3) var(--space-4);font-size:var(--text-xs);font-weight:700;
|
||||
text-transform:uppercase;letter-spacing:.05em;color:var(--c-text-secondary);
|
||||
border-bottom:1px solid var(--c-border)">
|
||||
Veröffentlichte Posts (letzte 50)
|
||||
</div>
|
||||
<div class="adm-table-scroll">
|
||||
<table class="adm-table">
|
||||
<thead><tr>
|
||||
<th>Datum</th><th>Thema</th><th>Plattform</th>
|
||||
<th>Kategorie</th><th>Score</th><th>Manager</th><th>Link</th>
|
||||
</tr></thead>
|
||||
<tbody>${postRows || `<tr><td colspan="7" style="text-align:center;
|
||||
color:var(--c-text-muted);padding:var(--space-6)">Noch keine Posts</td></tr>`}</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// TAB: ANALYTICS
|
||||
async function _renderAnalytics(el) {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
Offline-Cache + Push Notifications + Tile-Cache
|
||||
============================================================ */
|
||||
|
||||
const CACHE_VERSION = 'by-v369';
|
||||
const CACHE_VERSION = 'by-v370';
|
||||
const CACHE_STATIC = `${CACHE_VERSION}-static`;
|
||||
const CACHE_TILES = 'ban-yaro-tiles-v1'; // bleibt über SW-Updates erhalten
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue