v1.0
This commit is contained in:
+48
-19
@@ -18,6 +18,11 @@
|
||||
</script>
|
||||
{% tailwind_css %}
|
||||
|
||||
{% if company_settings.favicon %}
|
||||
<link rel="icon" type="image/png" href="{{ company_settings.favicon.url }}">
|
||||
{% else %}
|
||||
<link rel="icon" type="image/png" href="{% static 'favicon.png' %}">
|
||||
{% endif %}
|
||||
|
||||
<style>
|
||||
:root {
|
||||
@@ -34,14 +39,18 @@
|
||||
onclick="toggleSidebar()"></div>
|
||||
|
||||
<!-- Sidebar -->
|
||||
<aside id="sidebar" class="fixed top-0 z-40 w-72 h-screen bg-slate-800 text-white transform -translate-x-full lg:translate-x-0 transition-transform duration-300 flex flex-col border-r border-white/20">
|
||||
|
||||
<div class="p-6 border-b border-white/20 " style="background-color: {{ company_settings.color }};">
|
||||
|
||||
<h2 class="text-xl font-bold">
|
||||
{{ company_settings.companyname|default:"Projektverwaltung" }}
|
||||
</h2>
|
||||
<aside id="sidebar" class="fixed top-0 z-40 w-72 h-screen bg-slate-800 text-white transform -translate-x-full lg:translate-x-0 transition-transform duration-300 flex flex-col border-r border-white/10">
|
||||
|
||||
<div class="px-5 py-5 border-b border-white/10">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="w-2 h-2 rounded-full flex-shrink-0" style="background:var(--company-color);"></div>
|
||||
<div>
|
||||
<p class="text-sm font-semibold text-white leading-none">
|
||||
{{ company_settings.companyname|default:"Projektverwaltung" }}
|
||||
</p>
|
||||
<p class="text-xs mt-1" style="color:rgba(255,255,255,.3);">Projektverwaltung</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<nav class="flex-1 p-4 space-y-2">
|
||||
@@ -60,7 +69,7 @@
|
||||
onclick="toggleProjects()"
|
||||
class="w-full flex items-center justify-between px-4 py-3 hover:bg-slate-700">
|
||||
|
||||
<span>{{ current_project.name|default:"Projekt wählen" }}</span>
|
||||
<span>Projekte</span>
|
||||
|
||||
<svg id="projectArrow"
|
||||
class="w-4 h-4 transition-transform"
|
||||
@@ -84,6 +93,21 @@
|
||||
</a>
|
||||
{% endfor %}
|
||||
|
||||
{# Trennlinie #}
|
||||
<div class="mx-4 my-1 border-t border-slate-700/60"></div>
|
||||
|
||||
<a href="{% url 'projects:add' %}"
|
||||
class="block px-8 py-3 hover:bg-slate-700 text-slate-400 hover:text-white transition-colors">
|
||||
Hinzufügen
|
||||
</a>
|
||||
|
||||
{% if archived_count %}
|
||||
<a href="{% url 'projects:archived' %}"
|
||||
class="block px-8 py-3 hover:bg-slate-700 text-slate-400 hover:text-white transition-colors">
|
||||
Archiviert ({{ archived_count }})
|
||||
</a>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -145,6 +169,11 @@
|
||||
Posten
|
||||
</a>
|
||||
|
||||
<a href="{% url 'invoices:invoices_payments_overview' %}"
|
||||
class="block px-8 py-3 hover:bg-slate-700 transition">
|
||||
Zahlungen
|
||||
</a>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -188,17 +217,17 @@
|
||||
|
||||
</nav>
|
||||
|
||||
<div class="p-4 border-t border-white/20">
|
||||
<div class="p-4 border-t border-white/10">
|
||||
{% if user.is_superuser %}
|
||||
<div class="w-full rounded-xl flex items-center justify-between px-4 py-3 hover:bg-slate-700 mb-4 border-white/20 border">
|
||||
<div class="w-full rounded-xl flex items-center justify-between px-4 py-3 hover:bg-slate-700 mb-4 border-white/10 border">
|
||||
<a href="{% url 'admin:index' %}">Admin</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="flex gap-2 w-full">
|
||||
<button id="theme-toggle" class="rounded-xl px-4 py-3 hover:bg-slate-700 border-white/20 border">🌙</button>
|
||||
<button id="theme-toggle" class="rounded-xl px-4 py-3 hover:bg-slate-700 border-white/10 border">🌙</button>
|
||||
<form method="post" action="{% url 'accounts:logout' %}" class="w-full">
|
||||
{% csrf_token %}
|
||||
<button class="w-full rounded-xl px-4 py-3 border-white/20 border" style="background-color: {{ company_settings.color }};">Abmelden</button>
|
||||
<button class="w-full rounded-xl px-4 py-3 border-white/10 border" style="background-color: {{ company_settings.color }};">Abmelden</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@@ -217,16 +246,16 @@
|
||||
<span class="ml-4 font-bold">{{ company_settings.companyname|default:"Projektverwaltung" }}</span>
|
||||
</header>
|
||||
<main class="flex-1 p-6 overflow-x-auto w-screen lg:w-auto">
|
||||
<div class="p-6 rounded-xl shadow mb-8 bg-white dark:bg-slate-800 text-slate-900 dark:text-white transition-colors">
|
||||
<h1 class="text-3xl font-bold">
|
||||
{% block header_title %}
|
||||
{% endblock %}
|
||||
{% block header %}
|
||||
<div class="border border-slate-100 dark:border-slate-700 p-6 rounded-xl shadow mb-8 bg-white dark:bg-slate-800 text-slate-900 dark:text-white transition-colors">
|
||||
<h1 class="text-xl font-bold">
|
||||
{% block header_title %}{% endblock %}
|
||||
</h1>
|
||||
<p class="text-slate-400 mt-1">
|
||||
{% block header_description %}
|
||||
{% endblock %}
|
||||
<p class="text-slate-400 mt-1 text-md">
|
||||
{% block header_description %}{% endblock %}
|
||||
</p>
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
{% endblock %}
|
||||
</main>
|
||||
|
||||
@@ -2,9 +2,7 @@
|
||||
|
||||
{% block title %}Dashboard{% endblock %}
|
||||
|
||||
{% block header_title %}
|
||||
Dashboard
|
||||
{% endblock %}
|
||||
{% block header_title %}Dashboard{% endblock %}
|
||||
|
||||
{% block header_description %}
|
||||
Willkommen {{ user.username }}
|
||||
@@ -12,103 +10,245 @@ Willkommen {{ user.username }}
|
||||
|
||||
{% block content %}
|
||||
|
||||
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 xl:grid-cols-4 gap-4 mb-8">
|
||||
<a href="{% url 'invoices:overview' %}" class="border border-white/20 p-6 rounded-xl shadow bg-white dark:bg-slate-800 text-slate-900 dark:text-white transition-colors">
|
||||
<div class="flex items-center gap-3 justify-center">
|
||||
<h2 class="text-xl font-bold">Rechnungswesen</h2>
|
||||
</div>
|
||||
</a>
|
||||
<!--
|
||||
<a href="" class="border border-white/20 p-6 rounded-xl shadow bg-white dark:bg-slate-800 text-slate-900 dark:text-white transition-colors">
|
||||
<div class="flex items-center gap-3 justify-center">
|
||||
<h2 class="text-xl font-bold">Finanzübersicht</h2>
|
||||
</div>
|
||||
</a>
|
||||
<a href="" class="border border-white/20 p-6 rounded-xl shadow bg-white dark:bg-slate-800 text-slate-900 dark:text-white transition-colors">
|
||||
<div class="flex items-center gap-3 justify-center">
|
||||
<h2 class="text-xl font-bold">Arbeitszeiten</h2>
|
||||
</div>
|
||||
</a> -->
|
||||
<a href="{% url 'inventory_global:overview' %}" class="border border-white/20 p-6 rounded-xl shadow bg-white dark:bg-slate-800 text-slate-900 dark:text-white transition-colors">
|
||||
<div class="flex items-center gap-3 justify-center">
|
||||
<h2 class="text-xl font-bold">Inventar</h2>
|
||||
</div>
|
||||
</a>
|
||||
<!--
|
||||
<a href="" class="border border-white/20 p-6 rounded-xl shadow bg-white dark:bg-slate-800 text-slate-900 dark:text-white transition-colors">
|
||||
<div class="flex items-center gap-3 justify-center">
|
||||
<h2 class="text-xl font-bold">Investitionen</h2>
|
||||
</div>
|
||||
</a>
|
||||
-->
|
||||
<a href="{% url 'accounts:overview' %}" class="border border-white/20 p-6 rounded-xl shadow bg-white dark:bg-slate-800 text-slate-900 dark:text-white transition-colors">
|
||||
<div class="flex items-center gap-3 justify-center">
|
||||
<h2 class="text-xl font-bold">Mitarbeiter</h2>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<a href="{% url 'masterdata:overview' %}" class="border border-white/20 p-6 rounded-xl shadow bg-white dark:bg-slate-800 text-slate-900 dark:text-white transition-colors">
|
||||
<div class="flex items-center gap-3 justify-center">
|
||||
<h2 class="text-xl font-bold">Einstellungen</h2>
|
||||
</div>
|
||||
</a>
|
||||
{# Navigation #}
|
||||
<div class="grid grid-cols-2 md:grid-cols-4 gap-2 mb-6">
|
||||
<a href="{% url 'invoices:overview' %}" class="group p-4 rounded-xl bg-white dark:bg-slate-800 border border-slate-100 dark:border-slate-700 hover:border-[var(--company-color)]/40 hover:shadow-sm transition-all duration-200">
|
||||
<p class="text-[11px] text-slate-400 mb-0.5">Modul</p>
|
||||
<p class="text-sm font-semibold text-slate-800 dark:text-white">Rechnungswesen</p>
|
||||
</a>
|
||||
<a href="{% url 'inventory_global:overview' %}" class="group p-4 rounded-xl bg-white dark:bg-slate-800 border border-slate-100 dark:border-slate-700 hover:border-[var(--company-color)]/40 hover:shadow-sm transition-all duration-200">
|
||||
<p class="text-[11px] text-slate-400 mb-0.5">Modul</p>
|
||||
<p class="text-sm font-semibold text-slate-800 dark:text-white">Inventar</p>
|
||||
</a>
|
||||
<a href="{% url 'accounts:overview' %}" class="group p-4 rounded-xl bg-white dark:bg-slate-800 border border-slate-100 dark:border-slate-700 hover:border-[var(--company-color)]/40 hover:shadow-sm transition-all duration-200">
|
||||
<p class="text-[11px] text-slate-400 mb-0.5">Modul</p>
|
||||
<p class="text-sm font-semibold text-slate-800 dark:text-white">Mitarbeiter</p>
|
||||
</a>
|
||||
<a href="{% url 'masterdata:overview' %}" class="group p-4 rounded-xl bg-white dark:bg-slate-800 border border-slate-100 dark:border-slate-700 hover:border-[var(--company-color)]/40 hover:shadow-sm transition-all duration-200">
|
||||
<p class="text-[11px] text-slate-400 mb-0.5">Modul</p>
|
||||
<p class="text-sm font-semibold text-slate-800 dark:text-white">Einstellungen</p>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
{# Haupt-Dashboard #}
|
||||
<div class="bg-white dark:bg-slate-800 rounded-2xl border border-slate-100 dark:border-slate-700 overflow-hidden mb-6">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="mb-8">
|
||||
<div class="p-6 rounded-xl shadow bg-white dark:bg-slate-800 text-slate-900 dark:text-white transition-colors">
|
||||
<div class="flex flex-col sm:flex-row sm:justify-between sm:items-center gap-4">
|
||||
<div>
|
||||
<h2 class="text-xl font-bold">Aktionen</h2>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col sm:flex-row gap-2">
|
||||
<a href="{% url 'projects:add' %}" class="btn btn-add">+ Projekt</a>
|
||||
</div>
|
||||
|
||||
{# KPIs #}
|
||||
<div class="px-5 pt-5 pb-4 border-b border-slate-100 dark:border-slate-700">
|
||||
<p class="text-[11px] font-semibold uppercase tracking-widest text-slate-400 mb-3">Handlungsbedarf</p>
|
||||
<div class="grid grid-cols-2 md:grid-cols-4 gap-2" id="kpiMetrics">
|
||||
<div class="rounded-xl bg-slate-100 dark:bg-slate-700 p-4 animate-pulse h-16"></div>
|
||||
<div class="rounded-xl bg-slate-100 dark:bg-slate-700 p-4 animate-pulse h-16"></div>
|
||||
<div class="rounded-xl bg-slate-100 dark:bg-slate-700 p-4 animate-pulse h-16"></div>
|
||||
<div class="rounded-xl bg-slate-100 dark:bg-slate-700 p-4 animate-pulse h-16"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if memberships %}
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
|
||||
{% for m in memberships %}
|
||||
<a href="{% url 'projects:overview' m.project.id %}"
|
||||
class="p-6 rounded-xl shadow hover:shadow-lg transition block text-white"
|
||||
style="background: linear-gradient(135deg, {{ m.project.color }}, {{ m.project.color }}ff);">
|
||||
<h2 class="text-xl font-bold">
|
||||
{{ m.project.name }}
|
||||
</h2>
|
||||
<p class="text-sm mt-2">
|
||||
Rolle: {{ m.get_role_display }}
|
||||
</p>
|
||||
</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="bg-white dark:bg-slate-800 border border-orange-500 rounded-xl p-6 text-orange-500">
|
||||
Du bist noch keinem aktiven Projekt zugewiesen.
|
||||
</div>
|
||||
{% endif %}
|
||||
{# Charts #}
|
||||
<div class="px-5 py-4 border-b border-slate-100 dark:border-slate-700">
|
||||
<p class="text-[11px] font-semibold uppercase tracking-widest text-slate-400 mb-3">Aktueller Monat</p>
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-2">
|
||||
|
||||
{% if archived_count %}
|
||||
<a href="{% url 'projects:archived' %}" class="text-sm text-slate-400 hover:text-slate-500">
|
||||
{{ archived_count }} archivierte
|
||||
{% if archived_count == 1 %}
|
||||
Projekt anzeigen
|
||||
{% else %}
|
||||
Projekte anzeigen
|
||||
{% endif %}
|
||||
</a>
|
||||
{% endif %}
|
||||
<div class="rounded-xl bg-slate-100 dark:bg-slate-700 p-4">
|
||||
<div class="flex items-center justify-between mb-3">
|
||||
<p class="text-xs font-semibold text-slate-600 dark:text-slate-300">Rechnungen</p>
|
||||
<a href="{% url 'invoices:invoices_invoices_overview' %}" class="text-[11px] text-[var(--company-color)] hover:underline">Alle →</a>
|
||||
</div>
|
||||
<div style="position:relative;height:120px;">
|
||||
<canvas id="invoiceChart" role="img" aria-label="Rechnungen nach Status"></canvas>
|
||||
</div>
|
||||
<div id="invoiceLegend" class="flex flex-wrap gap-x-2 gap-y-1 mt-3"></div>
|
||||
</div>
|
||||
|
||||
<div class="rounded-xl bg-slate-100 dark:bg-slate-700 p-4">
|
||||
<div class="flex items-center justify-between mb-3">
|
||||
<p class="text-xs font-semibold text-slate-600 dark:text-slate-300">Angebote</p>
|
||||
<a href="{% url 'invoices:invoices_offers_overview' %}" class="text-[11px] text-[var(--company-color)] hover:underline">Alle →</a>
|
||||
</div>
|
||||
<div style="position:relative;height:120px;">
|
||||
<canvas id="offerChart" role="img" aria-label="Angebote nach Status"></canvas>
|
||||
</div>
|
||||
<div id="offerLegend" class="flex flex-wrap gap-x-2 gap-y-1 mt-3"></div>
|
||||
</div>
|
||||
|
||||
<div class="rounded-xl bg-slate-100 dark:bg-slate-700 p-4">
|
||||
<div class="flex items-center justify-between mb-3">
|
||||
<p class="text-xs font-semibold text-slate-600 dark:text-slate-300">Mahnungen</p>
|
||||
<a href="{% url 'invoices:invoices_reminders_overview' %}" class="text-[11px] text-[var(--company-color)] hover:underline">Alle →</a>
|
||||
</div>
|
||||
<div style="position:relative;height:120px;">
|
||||
<canvas id="reminderChart" role="img" aria-label="Mahnungen nach Status"></canvas>
|
||||
</div>
|
||||
<div id="reminderLegend" class="flex flex-wrap gap-x-2 gap-y-1 mt-3"></div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# Kunden #}
|
||||
<div class="px-5 py-4">
|
||||
<p class="text-[11px] font-semibold uppercase tracking-widest text-slate-400 mb-3">Kunden</p>
|
||||
<div class="grid grid-cols-2 md:grid-cols-4 gap-2" id="customerMetrics">
|
||||
<div class="rounded-xl bg-slate-100 dark:bg-slate-700 p-4 animate-pulse h-16"></div>
|
||||
<div class="rounded-xl bg-slate-100 dark:bg-slate-700 p-4 animate-pulse h-16"></div>
|
||||
<div class="rounded-xl bg-slate-100 dark:bg-slate-700 p-4 animate-pulse h-16"></div>
|
||||
<div class="rounded-xl bg-slate-100 dark:bg-slate-700 p-4 animate-pulse h-16"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<script>
|
||||
window.URLS = {
|
||||
invoiceInfo: "{% url 'invoices:ajax_invoice_info' %}",
|
||||
offerInfo: "{% url 'invoices:ajax_offer_info' %}",
|
||||
reminderInfo: "{% url 'invoices:ajax_reminder_info' %}",
|
||||
customerInfo: "{% url 'invoices:ajax_customer_info' %}",
|
||||
kpiInfo: "{% url 'invoices:ajax_kpi_info' %}",
|
||||
};
|
||||
</script>
|
||||
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/4.4.1/chart.umd.js"></script>
|
||||
<script>
|
||||
const STATUS_META = {
|
||||
draft: { label: "Entwurf", color: "#94a3b8" },
|
||||
sent: { label: "Versendet", color: "#2a78d6" },
|
||||
paid: { label: "Bezahlt", color: "#1baf7a" },
|
||||
overdue: { label: "Überfällig", color: "#e34948" },
|
||||
canceled: { label: "Storniert", color: "#eb6834" },
|
||||
accepted: { label: "Akzeptiert", color: "#1baf7a" },
|
||||
rejected: { label: "Abgelehnt", color: "#e34948" },
|
||||
expired: { label: "Frist abgelaufen", color: "#eda100" },
|
||||
};
|
||||
|
||||
function buildDonut(canvasId, legendId, data) {
|
||||
const entries = Object.entries(data).filter(([, v]) => v > 0);
|
||||
if (!entries.length) {
|
||||
document.getElementById(canvasId).parentElement.innerHTML =
|
||||
'<p class="text-[11px] text-slate-400 text-center py-8">Keine Einträge diesen Monat</p>';
|
||||
return;
|
||||
}
|
||||
const keys = entries.map(([k]) => k);
|
||||
const values = entries.map(([, v]) => v);
|
||||
const colors = keys.map(k => (STATUS_META[k] || { color: "#888" }).color);
|
||||
const labels = keys.map(k => (STATUS_META[k] || { label: k }).label);
|
||||
const total = values.reduce((a, b) => a + b, 0);
|
||||
|
||||
new Chart(document.getElementById(canvasId), {
|
||||
type: 'doughnut',
|
||||
data: {
|
||||
labels,
|
||||
datasets: [{
|
||||
data: values,
|
||||
backgroundColor: colors,
|
||||
borderWidth: 0,
|
||||
hoverOffset: 3,
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
cutout: '72%',
|
||||
plugins: {
|
||||
legend: { display: false },
|
||||
tooltip: {
|
||||
callbacks: {
|
||||
label: ctx => ` ${ctx.label}: ${ctx.parsed} (${Math.round(ctx.parsed / total * 100)}%)`
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const legend = document.getElementById(legendId);
|
||||
keys.forEach((k, i) => {
|
||||
const item = document.createElement('span');
|
||||
item.className = 'flex items-center gap-1 text-[11px] text-slate-400 dark:text-slate-400';
|
||||
item.innerHTML = `
|
||||
<span style="width:6px;height:6px;border-radius:50%;background:${colors[i]};display:inline-block;flex-shrink:0;"></span>
|
||||
${labels[i]}: <span class="font-medium text-slate-700 dark:text-slate-200">${values[i]}</span>
|
||||
`;
|
||||
legend.appendChild(item);
|
||||
});
|
||||
}
|
||||
|
||||
async function fetchAndRender(url, canvasId, legendId) {
|
||||
try {
|
||||
const r = await fetch(url);
|
||||
if (!r.ok) throw new Error();
|
||||
buildDonut(canvasId, legendId, await r.json());
|
||||
} catch {
|
||||
document.getElementById(canvasId).parentElement.innerHTML =
|
||||
'<p class="text-[11px] text-slate-400 text-center py-8">Keine Daten</p>';
|
||||
}
|
||||
}
|
||||
|
||||
async function fetchKpis(url) {
|
||||
try {
|
||||
const r = await fetch(url);
|
||||
if (!r.ok) throw new Error();
|
||||
const d = await r.json();
|
||||
document.getElementById('kpiMetrics').innerHTML = `
|
||||
<a href="{% url 'invoices:invoices_invoices_overview' %}?status=overdue"
|
||||
class="rounded-xl bg-slate-100 dark:bg-slate-700 p-4 transition-colors block">
|
||||
<p class="text-[11px] text-slate-400 mb-1">Überfällige Rechnungen</p>
|
||||
<p class="text-2xl font-semibold ${d.overdue_invoices > 0 ? 'text-red-500' : 'text-slate-800 dark:text-white'}">${d.overdue_invoices}</p>
|
||||
</a>
|
||||
<a href="{% url 'invoices:invoices_invoices_overview' %}?status=sent"
|
||||
class="rounded-xl bg-slate-100 dark:bg-slate-700 p-4 transition-colors block">
|
||||
<p class="text-[11px] text-slate-400 mb-1">Offene Rechnungen</p>
|
||||
<p class="text-2xl font-semibold text-slate-800 dark:text-white">${d.open_invoices}</p>
|
||||
</a>
|
||||
<a href="{% url 'invoices:invoices_offers_overview' %}?status=sent"
|
||||
class="rounded-xl bg-slate-100 dark:bg-slate-700 p-4 transition-colors block">
|
||||
<p class="text-[11px] text-slate-400 mb-1">Offene Angebote</p>
|
||||
<p class="text-2xl font-semibold text-slate-800 dark:text-white">${d.open_offers}</p>
|
||||
</a>
|
||||
<a href="{% url 'invoices:invoices_reminders_overview' %}?status=sent"
|
||||
class="rounded-xl bg-slate-100 dark:bg-slate-700 p-4 transition-colors block">
|
||||
<p class="text-[11px] text-slate-400 mb-1">Offene Mahnungen</p>
|
||||
<p class="text-2xl font-semibold ${d.open_reminders > 0 ? 'text-amber-500' : 'text-slate-800 dark:text-white'}">${d.open_reminders}</p>
|
||||
</a>
|
||||
`;
|
||||
} catch {
|
||||
document.getElementById('kpiMetrics').innerHTML =
|
||||
'<p class="text-[11px] text-slate-400">Keine Daten</p>';
|
||||
}
|
||||
}
|
||||
|
||||
async function fetchCustomers(url) {
|
||||
try {
|
||||
const r = await fetch(url);
|
||||
if (!r.ok) throw new Error();
|
||||
const d = await r.json();
|
||||
document.getElementById('customerMetrics').innerHTML = `
|
||||
<div class="rounded-xl bg-slate-100 dark:bg-slate-700 p-4">
|
||||
<p class="text-[11px] text-slate-400 mb-1">Gesamt</p>
|
||||
<p class="text-2xl font-semibold text-slate-800 dark:text-white">${d.total}</p>
|
||||
</div>
|
||||
<div class="rounded-xl bg-slate-100 dark:bg-slate-700 p-4">
|
||||
<p class="text-[11px] text-slate-400 mb-1">Neue diese Woche</p>
|
||||
<p class="text-2xl font-semibold text-slate-800 dark:text-white">${d.new_this_week}</p>
|
||||
</div>
|
||||
<div class="rounded-xl bg-slate-100 dark:bg-slate-700 p-4">
|
||||
<p class="text-[11px] text-slate-400 mb-1">Privatkunden</p>
|
||||
<p class="text-2xl font-semibold text-slate-800 dark:text-white">${d.private}</p>
|
||||
</div>
|
||||
<div class="rounded-xl bg-slate-100 dark:bg-slate-700 p-4">
|
||||
<p class="text-[11px] text-slate-400 mb-1">Unternehmen</p>
|
||||
<p class="text-2xl font-semibold text-slate-800 dark:text-white">${d.companies}</p>
|
||||
</div>
|
||||
`;
|
||||
} catch {
|
||||
document.getElementById('customerMetrics').innerHTML =
|
||||
'<p class="text-[11px] text-slate-400">Keine Daten</p>';
|
||||
}
|
||||
}
|
||||
|
||||
fetchKpis(window.URLS.kpiInfo);
|
||||
fetchAndRender(window.URLS.invoiceInfo, 'invoiceChart', 'invoiceLegend');
|
||||
fetchAndRender(window.URLS.offerInfo, 'offerChart', 'offerLegend');
|
||||
fetchAndRender(window.URLS.reminderInfo, 'reminderChart', 'reminderLegend');
|
||||
fetchCustomers(window.URLS.customerInfo);
|
||||
</script>
|
||||
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user