Files
UniVerse/frontend/src/views/admin/AdminDashboardView.vue
T
serega404 a8d51df3f1
Backend CI / build-and-test (push) Successful in 40s
Frontend CI / build-and-check (push) Failing after 19s
🚀 Create and publish a Docker image / Detect changes in backend and frontend (push) Successful in 6s
🚀 Create and publish a Docker image / Build & publish backend image (push) Successful in 24s
🚀 Create and publish a Docker image / Build & publish frontend image (push) Successful in 27s
🚀 Create and publish a Docker image / Update stack on Portainer (push) Successful in 5s
feat: добавил эндпоинт для получения статистики админского дашборда
2026-05-30 01:23:57 +03:00

85 lines
2.6 KiB
Vue

<script setup lang="ts">
import { computed, onMounted, ref } from 'vue'
import GlassCard from '@/components/ui/GlassCard.vue'
import StatsWidget from '@/components/ui/StatsWidget.vue'
import StatusBadge from '@/components/ui/StatusBadge.vue'
import { syncApi, usersApi } from '@/api'
import type { AdminDashboardStatsDto, SyncStatusDto } from '@/api/types'
const stats = ref<AdminDashboardStatsDto | null>(null)
const syncStatus = ref<SyncStatusDto | null>(null)
const syncMeta = computed(() =>
syncStatus.value?.lastSyncAt
? `Последняя синхронизация: ${new Date(syncStatus.value.lastSyncAt).toLocaleString('ru-RU')}`
: 'Синхронизация ещё не выполнялась',
)
onMounted(async () => {
const [statsResult, syncResult] = await Promise.allSettled([usersApi.adminStats(), syncApi.status()])
if (statsResult.status === 'fulfilled') stats.value = statsResult.value
if (syncResult.status === 'fulfilled') syncStatus.value = syncResult.value
})
</script>
<template>
<div class="admin-dashboard page-content">
<h1 class="page-title">Дашборд администратора</h1>
<div class="stats-row">
<StatsWidget label="Пользователей" :value="stats?.usersCount ?? 0" icon="users" color="green" />
<StatsWidget label="Лекций" :value="stats?.lecturesCount ?? 0" icon="books" color="aqua" />
<StatsWidget
label="Записей"
:value="stats?.enrollmentsCount ?? 0"
icon="calendar-event"
color="orange"
/>
<StatsWidget
label="Отзывы на проверке"
:value="stats?.pendingReviewsCount ?? 0"
icon="message-circle"
color="purple"
/>
</div>
<div class="grid">
<GlassCard>
<div class="section-title">Состояние синхронизации расписания</div>
<StatusBadge :status="syncStatus?.status ?? 'pending'" />
<div class="sync-meta">{{ syncMeta }}</div>
<div class="sync-error" v-if="syncStatus?.lastResult?.error">
Ошибка: {{ syncStatus.lastResult.error }}
</div>
</GlassCard>
</div>
</div>
</template>
<style scoped>
.admin-dashboard {
display: flex;
flex-direction: column;
gap: 18px;
}
.stats-row {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
gap: 16px;
}
.grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
gap: 16px;
}
.sync-meta {
font-size: 12px;
color: var(--color-text-secondary);
margin-top: 6px;
}
.sync-error {
font-size: 12px;
color: var(--color-error);
margin-top: 8px;
}
</style>