first commit

This commit is contained in:
brusnitsyn
2026-03-23 00:51:38 +09:00
commit 07854e0a9d
110 changed files with 19528 additions and 0 deletions

View File

@@ -0,0 +1,137 @@
<template>
<AppLayout>
<template #header>
<div>
<Link :href="route('migrations.index')" class="inline-flex items-center text-primary hover:underline text-sm">
<i class="pi pi-arrow-left mr-1"></i> Назад к расписаниям
</Link>
<h2 class="text-xl font-bold mt-1">{{ schedule.name }}</h2>
</div>
</template>
<div class="grid gap-6">
<Card header="Информация о расписании">
<template #content>
<div class="grid grid-cols-2 gap-4">
<div>
<p class="text-sm text-muted-color">Исходная БД</p>
<p class="font-bold">{{ schedule.source_database?.name }}</p>
<p class="text-sm text-muted-color">{{ schedule.source_database?.host }}/{{ schedule.source_database?.database }}</p>
</div>
<div>
<p class="text-sm text-muted-color">Целевая БД</p>
<p class="font-bold">{{ schedule.target_database?.name }}</p>
<p class="text-sm text-muted-color">{{ schedule.target_database?.host }}/{{ schedule.target_database?.database }}</p>
</div>
<div>
<p class="text-sm text-muted-color">Расписание</p>
<p class="font-bold font-mono">{{ schedule.cron_expression }}</p>
<p class="text-sm text-muted-color">Часовой пояс: {{ schedule.timezone }}</p>
</div>
<div>
<p class="text-sm text-muted-color">Статус</p>
<Tag :value="schedule.is_active ? 'Активно' : 'Неактивно'"
:severity="schedule.is_active ? 'success' : 'secondary'" />
</div>
<div>
<p class="text-sm text-muted-color">Таблицы</p>
<p class="font-bold">{{ schedule.scheduled_tables?.length || 0 }} выбрано</p>
</div>
<div>
<p class="text-sm text-muted-color">Размер пакета</p>
<p class="font-bold">{{ schedule.batch_size }}</p>
</div>
</div>
<div class="flex gap-2 mt-6 pt-4 border-t border-surface">
<Button label="Запустить сейчас" icon="pi pi-play" severity="success"
@click="runNow" :loading="running" />
<Link :href="route('migrations.edit', schedule.id)">
<Button label="Редактировать" icon="pi pi-pencil" severity="secondary" />
</Link>
</div>
</template>
</Card>
<Card header="Запуски миграций">
<template #content>
<DataTable :value="runs" stripedRows>
<Column field="id" header="ID" sortable></Column>
<Column field="status" header="Статус">
<template #body="slotProps">
<Tag :value="getStatusLabel(slotProps.data.status)"
:severity="getStatusSeverity(slotProps.data.status)" />
</template>
</Column>
<Column field="total_tables" header="Таблиц"></Column>
<Column field="processed_tables" header="Обработано"></Column>
<Column field="migrated_rows" header="Строк мигрировано"></Column>
<Column field="started_at" header="Начало">
<template #body="slotProps">
{{ slotProps.data.started_at ? formatDate(slotProps.data.started_at) : '-' }}
</template>
</Column>
<Column field="completed_at" header="Завершение">
<template #body="slotProps">
{{ slotProps.data.completed_at ? formatDate(slotProps.data.completed_at) : '-' }}
</template>
</Column>
</DataTable>
</template>
</Card>
</div>
</AppLayout>
</template>
<script setup>
import { ref } from 'vue';
import { Link, router } from '@inertiajs/vue3';
import AppLayout from '@/Layouts/AppLayout.vue';
import Card from 'primevue/card';
import DataTable from 'primevue/datatable';
import Column from 'primevue/column';
import Button from 'primevue/button';
import Tag from 'primevue/tag';
const props = defineProps({
schedule: Object,
runs: Array,
});
const running = ref(false);
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';
};
const formatDate = (dateString) => {
return new Date(dateString).toLocaleString('ru-RU');
};
const runNow = () => {
if (confirm('Запустить эту миграцию сейчас?')) {
running.value = true;
router.post(route('migrations.run', props.schedule.id), {}, {
onFinish: () => {
running.value = false;
}
});
}
};
</script>