125 lines
4.8 KiB
Vue
125 lines
4.8 KiB
Vue
<template>
|
|
<AppLayout>
|
|
<template #header>
|
|
<h2 class="text-xl font-bold">Панель управления</h2>
|
|
</template>
|
|
|
|
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
|
|
<Card>
|
|
<template #content>
|
|
<div class="flex items-center">
|
|
<div class="p-3 bg-primary-100 dark:bg-primary-900 rounded-full">
|
|
<i class="pi pi-database text-primary text-xl"></i>
|
|
</div>
|
|
<div class="ml-4">
|
|
<p class="text-muted-color text-sm">Исходные БД</p>
|
|
<p class="text-2xl font-bold">{{ stats.source_databases }}</p>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
</Card>
|
|
|
|
<Card>
|
|
<template #content>
|
|
<div class="flex items-center">
|
|
<div class="p-3 bg-green-100 dark:bg-green-900 rounded-full">
|
|
<i class="pi pi-cloud-download text-green-600 dark:text-green-400 text-xl"></i>
|
|
</div>
|
|
<div class="ml-4">
|
|
<p class="text-muted-color text-sm">Целевые БД</p>
|
|
<p class="text-2xl font-bold">{{ stats.target_databases }}</p>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
</Card>
|
|
|
|
<Card>
|
|
<template #content>
|
|
<div class="flex items-center">
|
|
<div class="p-3 bg-purple-100 dark:bg-purple-900 rounded-full">
|
|
<i class="pi pi-table text-purple-600 dark:text-purple-400 text-xl"></i>
|
|
</div>
|
|
<div class="ml-4">
|
|
<p class="text-muted-color text-sm">Таблиц</p>
|
|
<p class="text-2xl font-bold">{{ stats.tables }}</p>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
</Card>
|
|
|
|
<Card>
|
|
<template #content>
|
|
<div class="flex items-center">
|
|
<div class="p-3 bg-orange-100 dark:bg-orange-900 rounded-full">
|
|
<i class="pi pi-calendar text-orange-600 dark:text-orange-400 text-xl"></i>
|
|
</div>
|
|
<div class="ml-4">
|
|
<p class="text-muted-color text-sm">Активных расписаний</p>
|
|
<p class="text-2xl font-bold">{{ stats.schedules }}</p>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
</Card>
|
|
</div>
|
|
|
|
<div class="mt-8">
|
|
<h3 class="text-lg font-bold mb-4">Последние запуски миграций</h3>
|
|
<Card>
|
|
<template #content>
|
|
<DataTable :value="recentMigrations" stripedRows>
|
|
<Column field="id" header="ID" sortable></Column>
|
|
<Column field="schedule_name" header="Расписание" sortable></Column>
|
|
<Column field="status" header="Статус">
|
|
<template #body="slotProps">
|
|
<Tag :value="getStatusLabel(slotProps.data.status)"
|
|
:severity="getStatusSeverity(slotProps.data.status)" />
|
|
</template>
|
|
</Column>
|
|
<Column field="started_at" header="Начало" sortable></Column>
|
|
<Column field="completed_at" header="Завершение" sortable></Column>
|
|
</DataTable>
|
|
</template>
|
|
</Card>
|
|
</div>
|
|
</AppLayout>
|
|
</template>
|
|
|
|
<script setup>
|
|
import AppLayout from '@/Layouts/AppLayout.vue';
|
|
import Card from 'primevue/card';
|
|
import DataTable from 'primevue/datatable';
|
|
import Column from 'primevue/column';
|
|
import Tag from 'primevue/tag';
|
|
|
|
const props = defineProps({
|
|
stats: {
|
|
type: Object,
|
|
required: true,
|
|
},
|
|
recentMigrations: {
|
|
type: Array,
|
|
required: true,
|
|
},
|
|
});
|
|
|
|
const getStatusLabel = (status) => {
|
|
const labels = {
|
|
pending: 'Ожидает',
|
|
running: 'Выполняется',
|
|
completed: 'Завершено',
|
|
failed: 'Ошибка',
|
|
};
|
|
return labels[status] || status;
|
|
};
|
|
|
|
const getStatusSeverity = (status) => {
|
|
const severityMap = {
|
|
pending: 'secondary',
|
|
running: 'info',
|
|
completed: 'success',
|
|
failed: 'danger',
|
|
};
|
|
return severityMap[status] || 'secondary';
|
|
};
|
|
</script>
|