Admin: Social-Media-Tab mit Manager-Übersicht, Plattform-Auswertung und Post-Nachweis, SW by-v370

This commit is contained in:
rene 2026-04-25 10:27:39 +02:00
parent e2bb1a4b2d
commit 4f58a784c7
3 changed files with 182 additions and 1 deletions

View file

@ -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) {