540 lines
15 KiB
PHP
540 lines
15 KiB
PHP
<?php
|
|
include "templates/Header.html";
|
|
?>
|
|
|
|
<style>
|
|
/* Dashboard Styles */
|
|
.dashboard-section {
|
|
margin-bottom: 30px;
|
|
}
|
|
|
|
.section-title {
|
|
font-size: 1.25rem;
|
|
font-weight: 600;
|
|
color: var(--primary-color);
|
|
margin-bottom: 20px;
|
|
padding-bottom: 10px;
|
|
border-bottom: 2px solid var(--primary-color);
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 10px;
|
|
}
|
|
|
|
/* Statistik-Karten */
|
|
.stats-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
|
|
gap: 15px;
|
|
margin-bottom: 20px;
|
|
}
|
|
|
|
.stat-card {
|
|
background: white;
|
|
border-radius: var(--radius-md);
|
|
padding: 20px;
|
|
border: 1px solid var(--border-color);
|
|
text-align: center;
|
|
transition: transform 0.2s, box-shadow 0.2s;
|
|
}
|
|
|
|
.stat-card:hover {
|
|
transform: translateY(-3px);
|
|
box-shadow: var(--shadow-md);
|
|
}
|
|
|
|
.stat-icon {
|
|
font-size: 2rem;
|
|
margin-bottom: 10px;
|
|
}
|
|
|
|
.stat-value {
|
|
font-size: 2rem;
|
|
font-weight: 700;
|
|
color: var(--primary-color);
|
|
line-height: 1;
|
|
}
|
|
|
|
.stat-label {
|
|
font-size: 0.875rem;
|
|
color: var(--text-muted);
|
|
margin-top: 5px;
|
|
}
|
|
|
|
.stat-card.subject { border-top: 4px solid #28a745; }
|
|
.stat-card.subject .stat-icon { color: #28a745; }
|
|
|
|
.stat-card.person { border-top: 4px solid #007bff; }
|
|
.stat-card.person .stat-icon { color: #007bff; }
|
|
|
|
.stat-card.corporate { border-top: 4px solid #fd7e14; }
|
|
.stat-card.corporate .stat-icon { color: #fd7e14; }
|
|
|
|
.stat-card.publisher { border-top: 4px solid #6f42c1; }
|
|
.stat-card.publisher .stat-icon { color: #6f42c1; }
|
|
|
|
.stat-card.classification { border-top: 4px solid #20c997; }
|
|
.stat-card.classification .stat-icon { color: #20c997; }
|
|
|
|
.stat-card.total { border-top: 4px solid var(--primary-color); }
|
|
.stat-card.total .stat-icon { color: var(--primary-color); }
|
|
|
|
/* Zwei-Spalten Layout */
|
|
.dashboard-row {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fit, minmax(400px, 1fr));
|
|
gap: 20px;
|
|
}
|
|
|
|
/* Listen-Karten */
|
|
.list-card {
|
|
background: white;
|
|
border-radius: var(--radius-md);
|
|
border: 1px solid var(--border-color);
|
|
overflow: hidden;
|
|
}
|
|
|
|
.list-card-header {
|
|
background: var(--bg-light);
|
|
padding: 12px 15px;
|
|
font-weight: 600;
|
|
color: var(--text-primary);
|
|
border-bottom: 1px solid var(--border-color);
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
}
|
|
|
|
.list-card-body {
|
|
padding: 0;
|
|
max-height: 300px;
|
|
overflow-y: auto;
|
|
}
|
|
|
|
.list-item {
|
|
padding: 10px 15px;
|
|
border-bottom: 1px solid var(--border-light);
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
transition: background 0.2s;
|
|
}
|
|
|
|
.list-item:hover {
|
|
background: var(--bg-light);
|
|
}
|
|
|
|
.list-item:last-child {
|
|
border-bottom: none;
|
|
}
|
|
|
|
.list-item-text {
|
|
flex: 1;
|
|
font-weight: 500;
|
|
color: var(--text-primary);
|
|
white-space: nowrap;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
margin-right: 10px;
|
|
}
|
|
|
|
.list-item-meta {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 10px;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.list-item-type {
|
|
font-size: 11px;
|
|
padding: 2px 8px;
|
|
border-radius: 10px;
|
|
background: var(--bg-light);
|
|
color: var(--text-muted);
|
|
}
|
|
|
|
.list-item-date {
|
|
font-size: 12px;
|
|
color: var(--text-muted);
|
|
}
|
|
|
|
.list-item-link {
|
|
color: var(--primary-color);
|
|
text-decoration: none;
|
|
}
|
|
|
|
.list-item-link:hover {
|
|
text-decoration: underline;
|
|
}
|
|
|
|
/* Qualitäts-Indikatoren */
|
|
.quality-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
|
|
gap: 10px;
|
|
}
|
|
|
|
.quality-item {
|
|
background: white;
|
|
border-radius: var(--radius-sm);
|
|
padding: 12px;
|
|
border: 1px solid var(--border-color);
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
}
|
|
|
|
.quality-label {
|
|
font-size: 0.875rem;
|
|
color: var(--text-muted);
|
|
}
|
|
|
|
.quality-value {
|
|
font-weight: 600;
|
|
font-size: 1.1rem;
|
|
}
|
|
|
|
.quality-value.warning {
|
|
color: #dc3545;
|
|
}
|
|
|
|
.quality-value.ok {
|
|
color: #28a745;
|
|
}
|
|
|
|
/* Loading */
|
|
.loading-spinner {
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
padding: 40px;
|
|
color: var(--text-muted);
|
|
}
|
|
|
|
.loading-spinner i {
|
|
font-size: 2rem;
|
|
margin-right: 10px;
|
|
}
|
|
|
|
/* Navigation Cards */
|
|
.nav-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
|
gap: 15px;
|
|
}
|
|
|
|
.nav-card {
|
|
background: white;
|
|
border-radius: var(--radius-md);
|
|
padding: 25px 20px;
|
|
border: 1px solid var(--border-color);
|
|
text-align: center;
|
|
text-decoration: none;
|
|
color: var(--text-primary);
|
|
transition: all 0.2s;
|
|
}
|
|
|
|
.nav-card:hover {
|
|
transform: translateY(-3px);
|
|
box-shadow: var(--shadow-md);
|
|
border-color: var(--primary-color);
|
|
color: var(--primary-color);
|
|
}
|
|
|
|
.nav-card-icon {
|
|
font-size: 2.5rem;
|
|
margin-bottom: 10px;
|
|
}
|
|
|
|
.nav-card-title {
|
|
font-weight: 600;
|
|
font-size: 1.1rem;
|
|
}
|
|
</style>
|
|
|
|
<!-- Main Content -->
|
|
<main class="main-content">
|
|
<div class="container">
|
|
|
|
<!-- Navigation -->
|
|
<div class="card dashboard-section">
|
|
<h2 class="section-title">
|
|
<i class="fas fa-th-large"></i> Normdateien verwalten
|
|
</h2>
|
|
|
|
<div class="nav-grid">
|
|
<a href="Subjects.php" class="nav-card">
|
|
<div class="nav-card-icon">🏷️</div>
|
|
<div class="nav-card-title">Schlagworte</div>
|
|
</a>
|
|
|
|
<a href="Persons.php" class="nav-card">
|
|
<div class="nav-card-icon">👥</div>
|
|
<div class="nav-card-title">Personen</div>
|
|
</a>
|
|
|
|
<a href="Corporates.php" class="nav-card">
|
|
<div class="nav-card-icon">🏢</div>
|
|
<div class="nav-card-title">Körperschaften</div>
|
|
</a>
|
|
|
|
<a href="Publishers.php" class="nav-card">
|
|
<div class="nav-card-icon">📚</div>
|
|
<div class="nav-card-title">Verlage</div>
|
|
</a>
|
|
|
|
<a href="Classifications.php" class="nav-card">
|
|
<div class="nav-card-icon">🗂️</div>
|
|
<div class="nav-card-title">Klassifikation</div>
|
|
</a>
|
|
|
|
<a href="Treeview.php" class="nav-card">
|
|
<div class="nav-card-icon">🌳</div>
|
|
<div class="nav-card-title">Klassifikationsbaum</div>
|
|
</a>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Übersicht Card -->
|
|
<div class="card dashboard-section">
|
|
<h2 class="section-title">
|
|
<i class="fas fa-chart-bar"></i> Übersicht
|
|
</h2>
|
|
|
|
<!-- Statistik-Karten -->
|
|
<div id="stats-container">
|
|
<div class="loading-spinner">
|
|
<i class="fas fa-circle-notch fa-spin"></i>
|
|
<span>Lade Statistiken...</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Aktivität & Qualität -->
|
|
<div class="dashboard-row dashboard-section">
|
|
|
|
<!-- Zuletzt geändert -->
|
|
<div class="list-card">
|
|
<div class="list-card-header">
|
|
<i class="fas fa-clock"></i> Zuletzt geändert
|
|
</div>
|
|
<div class="list-card-body" id="recently-modified">
|
|
<div class="loading-spinner">
|
|
<i class="fas fa-circle-notch fa-spin"></i>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Zuletzt hinzugefügt -->
|
|
<div class="list-card">
|
|
<div class="list-card-header">
|
|
<i class="fas fa-plus-circle"></i> Zuletzt hinzugefügt
|
|
</div>
|
|
<div class="list-card-body" id="recently-created">
|
|
<div class="loading-spinner">
|
|
<i class="fas fa-circle-notch fa-spin"></i>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<!-- Qualitäts-Check -->
|
|
<div class="card dashboard-section">
|
|
<h2 class="section-title">
|
|
<i class="fas fa-check-circle"></i> Qualitäts-Check
|
|
</h2>
|
|
<p class="text-muted mb-15">Einträge ohne Relationen (Waisen)</p>
|
|
<div id="quality-container">
|
|
<div class="loading-spinner">
|
|
<i class="fas fa-circle-notch fa-spin"></i>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
</main>
|
|
|
|
<script>
|
|
$(document).ready(function() {
|
|
loadDashboardStats();
|
|
});
|
|
|
|
function loadDashboardStats() {
|
|
$.get('/Thesaurus/ajax/getDashboardStats.php', function(data) {
|
|
var stats = typeof data === 'string' ? JSON.parse(data) : data;
|
|
|
|
if (stats.error) {
|
|
$('#stats-container').html('<div class="text-center text-muted p-4">Fehler beim Laden der Statistiken</div>');
|
|
return;
|
|
}
|
|
|
|
// Statistik-Karten rendern
|
|
renderStatsCards(stats);
|
|
|
|
// Zuletzt geändert
|
|
renderRecentList('#recently-modified', stats.recentlyModified);
|
|
|
|
// Zuletzt hinzugefügt
|
|
renderRecentList('#recently-created', stats.recentlyCreated);
|
|
|
|
// Qualitäts-Check
|
|
renderQualityCheck(stats);
|
|
|
|
}).fail(function() {
|
|
$('#stats-container').html('<div class="text-center text-muted p-4">Fehler beim Laden der Statistiken</div>');
|
|
});
|
|
}
|
|
|
|
function renderStatsCards(stats) {
|
|
var html = '<div class="stats-grid">';
|
|
|
|
html += '<div class="stat-card subject">';
|
|
html += '<div class="stat-icon">🏷️</div>';
|
|
html += '<div class="stat-value">' + formatNumber(stats.counts.Subject) + '</div>';
|
|
html += '<div class="stat-label">Schlagworte</div>';
|
|
html += '</div>';
|
|
|
|
html += '<div class="stat-card person">';
|
|
html += '<div class="stat-icon">👥</div>';
|
|
html += '<div class="stat-value">' + formatNumber(stats.counts.Person) + '</div>';
|
|
html += '<div class="stat-label">Personen</div>';
|
|
html += '</div>';
|
|
|
|
html += '<div class="stat-card corporate">';
|
|
html += '<div class="stat-icon">🏢</div>';
|
|
html += '<div class="stat-value">' + formatNumber(stats.counts.Corporate) + '</div>';
|
|
html += '<div class="stat-label">Körperschaften</div>';
|
|
html += '</div>';
|
|
|
|
html += '<div class="stat-card publisher">';
|
|
html += '<div class="stat-icon">📚</div>';
|
|
html += '<div class="stat-value">' + formatNumber(stats.counts.Publisher) + '</div>';
|
|
html += '<div class="stat-label">Verlage</div>';
|
|
html += '</div>';
|
|
|
|
html += '<div class="stat-card classification">';
|
|
html += '<div class="stat-icon">🗂️</div>';
|
|
html += '<div class="stat-value">' + formatNumber(stats.counts.Classification) + '</div>';
|
|
html += '<div class="stat-label">Klassifikationen</div>';
|
|
html += '</div>';
|
|
|
|
html += '<div class="stat-card total">';
|
|
html += '<div class="stat-icon"><i class="fas fa-database"></i></div>';
|
|
html += '<div class="stat-value">' + formatNumber(stats.total) + '</div>';
|
|
html += '<div class="stat-label">Gesamt</div>';
|
|
html += '</div>';
|
|
|
|
html += '</div>';
|
|
|
|
// Zusätzliche Info-Zeile
|
|
html += '<div class="d-flex gap-4 mt-15 text-muted" style="font-size: 0.9rem;">';
|
|
html += '<span><i class="fas fa-link me-1"></i> ' + formatNumber(stats.relationsTotal) + ' Relationen</span>';
|
|
html += '<span><i class="fas fa-check me-1"></i> ' + formatNumber(stats.descriptors) + ' Deskriptoren</span>';
|
|
html += '<span><i class="fas fa-times me-1"></i> ' + formatNumber(stats.nonDescriptors) + ' Non-Deskriptoren</span>';
|
|
html += '</div>';
|
|
|
|
$('#stats-container').html(html);
|
|
}
|
|
|
|
function renderRecentList(container, items) {
|
|
if (!items || items.length === 0) {
|
|
$(container).html('<div class="text-center text-muted p-4">Keine Einträge</div>');
|
|
return;
|
|
}
|
|
|
|
var html = '';
|
|
items.forEach(function(item) {
|
|
var typeLabel = getTypeLabel(item.type);
|
|
var link = getTypeLink(item.type, item.id);
|
|
var date = formatDate(item.date);
|
|
|
|
html += '<div class="list-item">';
|
|
html += '<a href="' + link + '" class="list-item-text list-item-link" title="' + escapeHtml(item.text) + '">' + escapeHtml(item.text) + '</a>';
|
|
html += '<div class="list-item-meta">';
|
|
html += '<span class="list-item-type">' + typeLabel + '</span>';
|
|
html += '<span class="list-item-date">' + date + '</span>';
|
|
html += '</div>';
|
|
html += '</div>';
|
|
});
|
|
|
|
$(container).html(html);
|
|
}
|
|
|
|
function renderQualityCheck(stats) {
|
|
var html = '<div class="quality-grid">';
|
|
|
|
var types = [
|
|
{ key: 'Subject', label: 'Schlagworte', icon: '🏷️' },
|
|
{ key: 'Person', label: 'Personen', icon: '👥' },
|
|
{ key: 'Corporate', label: 'Körperschaften', icon: '🏢' },
|
|
{ key: 'Publisher', label: 'Verlage', icon: '📚' },
|
|
{ key: 'Classification', label: 'Klassifikation', icon: '🗂️' }
|
|
];
|
|
|
|
types.forEach(function(type) {
|
|
var count = stats.orphans[type.key] || 0;
|
|
var valueClass = count > 0 ? 'warning' : 'ok';
|
|
|
|
html += '<div class="quality-item">';
|
|
html += '<span class="quality-label">' + type.icon + ' ' + type.label + '</span>';
|
|
html += '<span class="quality-value ' + valueClass + '">' + formatNumber(count) + '</span>';
|
|
html += '</div>';
|
|
});
|
|
|
|
html += '</div>';
|
|
|
|
// Gesamt-Waisen
|
|
var totalOrphans = stats.orphansTotal || 0;
|
|
html += '<div class="mt-15 text-muted" style="font-size: 0.9rem;">';
|
|
html += '<i class="fas fa-exclamation-triangle me-1"></i> ';
|
|
html += 'Gesamt: <strong>' + formatNumber(totalOrphans) + '</strong> Einträge ohne Relationen';
|
|
html += '</div>';
|
|
|
|
$('#quality-container').html(html);
|
|
}
|
|
|
|
function getTypeLabel(type) {
|
|
var labels = {
|
|
'Subject': 'Schlagwort',
|
|
'Person': 'Person',
|
|
'Corporate': 'Körperschaft',
|
|
'Publisher': 'Verlag',
|
|
'Classification': 'Klassifikation'
|
|
};
|
|
return labels[type] || type;
|
|
}
|
|
|
|
function getTypeLink(type, id) {
|
|
var links = {
|
|
'Subject': 'Subjects.php?edit=',
|
|
'Person': 'Persons.php?edit=',
|
|
'Corporate': 'Corporates.php?edit=',
|
|
'Publisher': 'Publishers.php?edit=',
|
|
'Classification': 'Classifications.php?edit='
|
|
};
|
|
return (links[type] || 'Subjects.php?edit=') + id;
|
|
}
|
|
|
|
function formatNumber(num) {
|
|
if (!num) return '0';
|
|
return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ".");
|
|
}
|
|
|
|
function formatDate(dateStr) {
|
|
if (!dateStr || dateStr === '0000-00-00 00:00:00') return '-';
|
|
var date = new Date(dateStr);
|
|
return date.toLocaleDateString('de-DE', { day: '2-digit', month: '2-digit', year: 'numeric' });
|
|
}
|
|
|
|
function escapeHtml(text) {
|
|
if (!text) return '';
|
|
var div = document.createElement('div');
|
|
div.textContent = text;
|
|
return div.innerHTML;
|
|
}
|
|
</script>
|
|
|
|
<?php
|
|
include "templates/Footer.html";
|
|
?>
|