- Объединены ресурсы в 5 логических групп: Контент сайта, Бронирования, Отзывы и рейтинги, Персонал и гиды, Администрирование - Удалены дублирующие настройки navigation для чистой группировки - Добавлены CSS стили для визуального отображения иерархии с отступами - Добавлены эмодзи-иконки для каждого типа ресурсов через CSS - Улучшена навигация с правильной вложенностью элементов
282 lines
11 KiB
HTML
282 lines
11 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="ru">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>Планировщик рабочих смен - Корея Тур Агентство</title>
|
||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
|
||
<style>
|
||
body {
|
||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||
min-height: 100vh;
|
||
padding: 20px 0;
|
||
}
|
||
|
||
.main-container {
|
||
background: white;
|
||
border-radius: 15px;
|
||
box-shadow: 0 20px 40px rgba(0,0,0,0.1);
|
||
overflow: hidden;
|
||
}
|
||
|
||
.header-section {
|
||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||
color: white;
|
||
padding: 30px;
|
||
text-align: center;
|
||
}
|
||
|
||
.header-title {
|
||
font-size: 2.5rem;
|
||
font-weight: 700;
|
||
margin-bottom: 10px;
|
||
}
|
||
|
||
.header-subtitle {
|
||
font-size: 1.1rem;
|
||
opacity: 0.9;
|
||
}
|
||
|
||
.back-button {
|
||
position: absolute;
|
||
top: 20px;
|
||
left: 20px;
|
||
color: white;
|
||
text-decoration: none;
|
||
padding: 10px 15px;
|
||
background: rgba(255,255,255,0.2);
|
||
border-radius: 8px;
|
||
transition: all 0.3s;
|
||
}
|
||
|
||
.back-button:hover {
|
||
background: rgba(255,255,255,0.3);
|
||
color: white;
|
||
text-decoration: none;
|
||
}
|
||
|
||
.content-section {
|
||
padding: 30px;
|
||
}
|
||
|
||
.loading-spinner {
|
||
text-align: center;
|
||
padding: 60px;
|
||
}
|
||
|
||
.spinner-border {
|
||
width: 4rem;
|
||
height: 4rem;
|
||
}
|
||
|
||
.error-message {
|
||
text-align: center;
|
||
padding: 60px;
|
||
color: #dc3545;
|
||
}
|
||
|
||
.error-icon {
|
||
font-size: 4rem;
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
/* Адаптивность */
|
||
@media (max-width: 768px) {
|
||
.header-title {
|
||
font-size: 2rem;
|
||
}
|
||
|
||
.content-section {
|
||
padding: 20px;
|
||
}
|
||
|
||
body {
|
||
padding: 10px;
|
||
}
|
||
}
|
||
|
||
/* Анимации */
|
||
.main-container {
|
||
animation: slideUp 0.6s ease-out;
|
||
}
|
||
|
||
@keyframes slideUp {
|
||
from {
|
||
transform: translateY(30px);
|
||
opacity: 0;
|
||
}
|
||
to {
|
||
transform: translateY(0);
|
||
opacity: 1;
|
||
}
|
||
}
|
||
|
||
.fade-in {
|
||
animation: fadeIn 0.8s ease-out;
|
||
}
|
||
|
||
@keyframes fadeIn {
|
||
from {
|
||
opacity: 0;
|
||
}
|
||
to {
|
||
opacity: 1;
|
||
}
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="container-fluid">
|
||
<div class="row justify-content-center">
|
||
<div class="col-12">
|
||
<div class="main-container">
|
||
<!-- Header -->
|
||
<div class="header-section position-relative">
|
||
<a href="/admin" class="back-button">
|
||
<i class="fas fa-arrow-left me-2"></i>Назад в админку
|
||
</a>
|
||
|
||
<div class="header-title">
|
||
<i class="fas fa-calendar-week me-3"></i>
|
||
Планировщик рабочих смен
|
||
</div>
|
||
<div class="header-subtitle">
|
||
Управление расписанием работы гидов
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Content -->
|
||
<div class="content-section">
|
||
<!-- Loading State -->
|
||
<div id="loading" class="loading-spinner">
|
||
<div class="spinner-border text-primary" role="status">
|
||
<span class="visually-hidden">Загрузка...</span>
|
||
</div>
|
||
<div class="mt-3">
|
||
<h5>Загрузка планировщика смен...</h5>
|
||
<p class="text-muted">Подождите, пожалуйста</p>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Error State -->
|
||
<div id="error" class="error-message" style="display: none;">
|
||
<div class="error-icon">
|
||
<i class="fas fa-exclamation-triangle"></i>
|
||
</div>
|
||
<h4>Ошибка загрузки</h4>
|
||
<p>Не удалось загрузить планировщик смен. Попробуйте перезагрузить страницу.</p>
|
||
<button class="btn btn-primary" onclick="location.reload()">
|
||
<i class="fas fa-redo me-2"></i>Перезагрузить
|
||
</button>
|
||
</div>
|
||
|
||
<!-- Schedule Manager Container -->
|
||
<div id="scheduleManagerContainer" class="fade-in" style="display: none;">
|
||
<!-- Компонент будет загружен здесь -->
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Bootstrap JS -->
|
||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||
|
||
<!-- Schedule Manager Component -->
|
||
<script src="/components/guide-schedule-manager.js"></script>
|
||
|
||
<script>
|
||
document.addEventListener('DOMContentLoaded', function() {
|
||
let retryCount = 0;
|
||
const maxRetries = 3;
|
||
|
||
async function initializeScheduleManager() {
|
||
try {
|
||
// Проверяем доступность компонента
|
||
if (typeof GuideScheduleManager === 'undefined') {
|
||
throw new Error('GuideScheduleManager component not loaded');
|
||
}
|
||
|
||
// Инициализируем планировщик смен
|
||
const scheduleManager = new GuideScheduleManager({
|
||
container: document.getElementById('scheduleManagerContainer'),
|
||
onScheduleChange: function(scheduleData) {
|
||
console.log('Расписание изменено:', scheduleData);
|
||
|
||
// Можно добавить уведомления об успешном сохранении
|
||
showNotification('Расписание успешно сохранено!', 'success');
|
||
}
|
||
});
|
||
|
||
// Показываем контейнер и скрываем загрузку
|
||
document.getElementById('loading').style.display = 'none';
|
||
document.getElementById('scheduleManagerContainer').style.display = 'block';
|
||
|
||
console.log('Планировщик смен инициализирован успешно');
|
||
|
||
} catch (error) {
|
||
console.error('Ошибка инициализации планировщика смен:', error);
|
||
|
||
if (retryCount < maxRetries) {
|
||
retryCount++;
|
||
console.log(`Попытка повторной загрузки ${retryCount}/${maxRetries}`);
|
||
setTimeout(initializeScheduleManager, 2000);
|
||
} else {
|
||
// Показываем ошибку
|
||
document.getElementById('loading').style.display = 'none';
|
||
document.getElementById('error').style.display = 'block';
|
||
}
|
||
}
|
||
}
|
||
|
||
// Функция для показа уведомлений
|
||
function showNotification(message, type = 'info') {
|
||
// Создаем контейнер для уведомлений если его нет
|
||
let container = document.getElementById('notification-container');
|
||
if (!container) {
|
||
container = document.createElement('div');
|
||
container.id = 'notification-container';
|
||
container.style.cssText = 'position: fixed; top: 20px; right: 20px; z-index: 9999;';
|
||
document.body.appendChild(container);
|
||
}
|
||
|
||
// Создаем уведомление
|
||
const notification = document.createElement('div');
|
||
notification.className = `alert alert-${type} alert-dismissible fade show`;
|
||
notification.style.cssText = 'min-width: 300px; margin-bottom: 10px;';
|
||
notification.innerHTML = `
|
||
${message}
|
||
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
||
`;
|
||
|
||
container.appendChild(notification);
|
||
|
||
// Автоматически удаляем через 5 секунд
|
||
setTimeout(() => {
|
||
if (notification.parentNode) {
|
||
notification.remove();
|
||
}
|
||
}, 5000);
|
||
}
|
||
|
||
// Глобальная функция для уведомлений
|
||
window.showNotification = showNotification;
|
||
|
||
// Запускаем инициализацию после небольшой задержки
|
||
setTimeout(initializeScheduleManager, 500);
|
||
});
|
||
|
||
// Обработка ошибок загрузки скриптов
|
||
window.addEventListener('error', function(e) {
|
||
if (e.filename && e.filename.includes('guide-schedule-manager.js')) {
|
||
console.error('Ошибка загрузки компонента планировщика смен:', e);
|
||
document.getElementById('loading').style.display = 'none';
|
||
document.getElementById('error').style.display = 'block';
|
||
}
|
||
});
|
||
</script>
|
||
</body>
|
||
</html> |