147 lines
4.4 KiB
Vue
147 lines
4.4 KiB
Vue
<template>
|
|
<private-view title="Overview">
|
|
<div class="dashboard">
|
|
<header class="dashboard-header">
|
|
<h1 class="title">Infrastructure Stack</h1>
|
|
<p class="subtitle">Zentrale Schnittstelle für Firmen, Personen und Leads.</p>
|
|
</header>
|
|
|
|
<div class="stats-grid">
|
|
<div class="stat-card" @click="navigateTo('company-manager')">
|
|
<div class="stat-icon"><v-icon name="business" large /></div>
|
|
<div class="stat-content">
|
|
<span class="stat-label">Firmen</span>
|
|
<span class="stat-value">{{ stats.companies }}</span>
|
|
</div>
|
|
<v-icon name="chevron_right" class="arrow" />
|
|
</div>
|
|
|
|
<div class="stat-card" @click="navigateTo('people-manager')">
|
|
<div class="stat-icon"><v-icon name="person" large /></div>
|
|
<div class="stat-content">
|
|
<span class="stat-label">Personen</span>
|
|
<span class="stat-value">{{ stats.people }}</span>
|
|
</div>
|
|
<v-icon name="chevron_right" class="arrow" />
|
|
</div>
|
|
|
|
<div class="stat-card" @click="navigateTo('acquisition-manager')">
|
|
<div class="stat-icon"><v-icon name="auto_awesome" large /></div>
|
|
<div class="stat-content">
|
|
<span class="stat-label">Leads</span>
|
|
<span class="stat-value">{{ stats.leads }}</span>
|
|
</div>
|
|
<v-icon name="chevron_right" class="arrow" />
|
|
</div>
|
|
</div>
|
|
|
|
<div class="recent-activity">
|
|
<h2 class="section-title">Schnellzugriff</h2>
|
|
<div class="action-grid">
|
|
<v-button secondary block @click="navigateTo('people-manager', { create: 'true' })">
|
|
<v-icon name="person_add" left />
|
|
Neue Person anlegen
|
|
</v-button>
|
|
<v-button secondary block @click="navigateTo('acquisition-manager', { create: 'true' })">
|
|
<v-icon name="add_link" left />
|
|
Neuen Lead registrieren
|
|
</v-button>
|
|
<v-button secondary block @click="navigateTo('customer-manager', { create: 'true' })">
|
|
<v-icon name="handshake" left />
|
|
Kunden verlinken
|
|
</v-button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</private-view>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { ref, onMounted } from 'vue';
|
|
import { useApi } from '@directus/extensions-sdk';
|
|
import { useRouter } from 'vue-router';
|
|
|
|
const api = useApi();
|
|
const router = useRouter();
|
|
|
|
const stats = ref({
|
|
companies: 0,
|
|
people: 0,
|
|
leads: 0
|
|
});
|
|
|
|
async function fetchStats() {
|
|
try {
|
|
const [comp, peop, lead] = await Promise.all([
|
|
api.get('/items/companies?aggregate[count]=*'),
|
|
api.get('/items/people?aggregate[count]=*'),
|
|
api.get('/items/leads?aggregate[count]=*')
|
|
]);
|
|
stats.value = {
|
|
companies: comp.data.data[0].count,
|
|
people: peop.data.data[0].count,
|
|
leads: lead.data.data[0].count
|
|
};
|
|
} catch (error) {
|
|
console.error('Failed to fetch stats:', error);
|
|
}
|
|
}
|
|
|
|
function navigateTo(id: string, query?: any) {
|
|
console.log(`[Unified Dashboard] Navigating to ${id}...`);
|
|
router.push({ name: id, query });
|
|
}
|
|
|
|
onMounted(fetchStats);
|
|
</script>
|
|
|
|
<style scoped>
|
|
.dashboard { padding: 40px; }
|
|
.dashboard-header { margin-bottom: 48px; }
|
|
.title { font-size: 32px; font-weight: 800; letter-spacing: -0.5px; margin-bottom: 8px; }
|
|
.subtitle { color: var(--theme--foreground-subdued); font-size: 16px; }
|
|
|
|
.stats-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 24px; margin-bottom: 48px; }
|
|
|
|
.stat-card {
|
|
background: var(--theme--background-normal);
|
|
border: 1px solid var(--theme--border);
|
|
padding: 24px;
|
|
border-radius: 12px;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 20px;
|
|
cursor: pointer;
|
|
transition: all 0.2s ease;
|
|
position: relative;
|
|
}
|
|
|
|
.stat-card:hover {
|
|
border-color: var(--theme--primary);
|
|
transform: translateY(-2px);
|
|
box-shadow: 0 8px 16px rgba(0,0,0,0.1);
|
|
}
|
|
|
|
.stat-icon {
|
|
width: 56px;
|
|
height: 56px;
|
|
background: var(--theme--background-subdued);
|
|
border-radius: 12px;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
color: var(--theme--primary);
|
|
}
|
|
|
|
.stat-content { display: flex; flex-direction: column; }
|
|
.stat-label { font-size: 12px; font-weight: 700; text-transform: uppercase; color: var(--theme--foreground-subdued); letter-spacing: 0.5px; }
|
|
.stat-value { font-size: 28px; font-weight: 800; color: var(--theme--foreground); }
|
|
|
|
.arrow { position: absolute; right: 24px; opacity: 0.2; }
|
|
.stat-card:hover .arrow { opacity: 1; color: var(--theme--primary); }
|
|
|
|
.recent-activity { max-width: 600px; }
|
|
.section-title { font-size: 18px; font-weight: 700; margin-bottom: 24px; }
|
|
.action-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
|
|
</style>
|