commit 08.01

This commit is contained in:
Владимир
2026-01-08 12:38:09 +00:00
parent bbe639b604
commit f5c68bf0c7
13 changed files with 4444 additions and 542 deletions

218
public/services.html Normal file
View File

@@ -0,0 +1,218 @@
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Выбор услуги - КлинСервис</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: Arial, sans-serif; background: #f8f9fa; }
/* Хедер */
header {
background: white; padding: 20px 50px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
position: sticky; top: 0; z-index: 100;
}
.header-content {
max-width: 1200px; margin: 0 auto;
display: flex; justify-content: space-between; align-items: center;
}
.logo { font-size: 24px; font-weight: bold; color: #667eea; }
.header-nav { display: flex; gap: 20px; align-items: center; }
.btn {
padding: 10px 20px; border: none; border-radius: 25px;
cursor: pointer; font-size: 14px; text-decoration: none;
display: inline-block; transition: all 0.3s;
}
.btn-primary { background: #667eea; color: white; }
.btn-primary:hover { background: #5a67d8; }
.btn-secondary { background: transparent; color: #667eea; border: 2px solid #667eea; }
.btn-secondary:hover { background: #667eea; color: white; }
/* Контейнер */
.container { max-width: 1000px; margin: 40px auto; padding: 0 20px; }
h1 { text-align: center; color: #333; margin-bottom: 40px; font-size: 32px; }
/* Форма выбора */
.selection-form {
background: white; padding: 40px; border-radius: 20px;
box-shadow: 0 20px 40px rgba(0,0,0,0.1); margin-bottom: 40px;
}
.form-row { display: grid; grid-template-columns: 1fr 1fr; gap: 30px; margin-bottom: 30px; }
@media (max-width: 768px) { .form-row { grid-template-columns: 1fr; } }
label { display: block; margin-bottom: 10px; font-weight: bold; color: #555; }
select, input {
width: 100%; padding: 15px; border: 2px solid #e9ecef;
border-radius: 10px; font-size: 16px; transition: border-color 0.3s;
}
select:focus, input:focus { outline: none; border-color: #667eea; }
/* Простой календарь */
.calendar-section {
background: white; padding: 40px; border-radius: 20px;
box-shadow: 0 20px 40px rgba(0,0,0,0.1);
}
.calendar-header {
display: flex; justify-content: space-between; align-items: center;
margin-bottom: 20px; flex-wrap: wrap; gap: 10px;
}
.calendar-nav-btn {
padding: 10px 20px; background: #667eea; color: white;
border: none; border-radius: 10px; cursor: pointer;
}
.calendar-nav-btn:hover { background: #5a67d8; }
.calendar-nav-btn:disabled { background: #ccc; cursor: not-allowed; }
.month-year { font-size: 24px; font-weight: bold; color: #333; }
.calendar-grid {
display: grid; grid-template-columns: repeat(7, 1fr);
gap: 5px; text-align: center;
}
.calendar-day {
padding: 15px; border: 1px solid #e9ecef;
border-radius: 10px; cursor: pointer; transition: all 0.3s;
font-weight: 500;
}
.calendar-day:hover { background: #e3f2fd; border-color: #667eea; }
.calendar-day.other-month { color: #ccc; }
.calendar-day.selected {
background: #667eea; color: white; box-shadow: 0 5px 15px rgba(102,126,234,0.4);
}
.calendar-day.disabled {
background: #f8f9fa; color: #ccc; cursor: not-allowed;
}
.weekdays { font-weight: bold; color: #555; padding: 10px 0; }
/* Слоты */
.slots-section {
background: white; padding: 40px; border-radius: 20px;
box-shadow: 0 20px 40px rgba(0,0,0,0.1); margin-top: 30px;
}
.slots-grid { display: flex; flex-wrap: wrap; gap: 15px; }
.slot {
padding: 15px 25px; background: #f8f9fa;
border: 2px solid transparent; border-radius: 25px;
cursor: pointer; transition: all 0.3s; font-weight: 500;
}
.slot:hover { background: #e3f2fd; border-color: #667eea; }
.slot.selected { background: #667eea; color: white; border-color: #5a67d8; }
.slot.booked { background: #f8d7da; color: #721c24; cursor: not-allowed; }
.no-slots { text-align: center; color: #666; padding: 40px; font-style: italic; }
/* Кнопка забронировать */
.book-btn {
width: 100%; padding: 20px; background: #28a745;
color: white; border: none; border-radius: 15px;
font-size: 20px; font-weight: bold; cursor: pointer;
margin-top: 30px; transition: all 0.3s;
}
.book-btn:hover:not(:disabled) { background: #218838; transform: translateY(-2px); }
.book-btn:disabled { background: #ccc; cursor: not-allowed; }
</style>
</head>
<body>
<!-- Хедер -->
<header>
<div class="header-content">
<div class="logo">🧹 КлинСервис</div>
<div class="header-nav">
<a href="index.html" class="btn btn-secondary">Главная</a>
<a href="my-bookings.html" class="btn btn-secondary" id="profileBtn" style="display:none;">Мои брони</a>
<button class="btn btn-primary" id="logoutBtn" style="display:none;" onclick="logout()">Выйти</button>
</div>
</div>
</header>
<div class="container">
<h1>📅 Выберите дату и время</h1>
<!-- Выбор услуги -->
<div class="selection-form">
<div class="form-row">
<div>
<label>Услуга *</label>
<select id="serviceSelect">
<option value="">Загрузка...</option>
</select>
</div>
<div>
<label>Длительность</label>
<input type="text" id="duration" readonly placeholder="Выберите услугу">
</div>
</div>
<button class="book-btn" id="bookBtn" onclick="bookService()" disabled>
Выбрать время →
</button>
</div>
<!-- Календарь -->
<div class="calendar-section">
<div class="calendar-header">
<button class="calendar-nav-btn" onclick="prevMonth()">← Месяц</button>
<div class="month-year" id="monthYear"></div>
<button class="calendar-nav-btn" onclick="nextMonth()">Месяц →</button>
</div>
<div class="calendar-grid">
<div class="weekdays">Пн</div><div class="weekdays">Вт</div><div class="weekdays">Ср</div>
<div class="weekdays">Чт</div><div class="weekdays">Пт</div><div class="weekdays">Сб</div><div class="weekdays">Вс</div>
<div id="calendarDays"></div>
</div>
</div>
<!-- Слоты времени -->
<div class="slots-section" id="slotsSection" style="display:none;">
<h3>Доступные слоты</h3>
<div class="slots-grid" id="slotsGrid"></div>
<button class="book-btn" id="confirmBookingBtn" onclick="confirmBooking()" style="display:none;">
✅ Забронировать
</button>
</div>
</div>
<script>
let services = [];
let selectedServiceId = null;
let selectedDate = null;
let currentMonth = new Date().getMonth();
let currentYear = new Date().getFullYear();
let availableSlots = [];
let token = localStorage.getItem('token');
// Проверка авторизации
if (!token) {
window.location.href = 'register-login.html';
throw new Error('Нужна авторизация');
}
updateHeader();
// 1. Загрузить услуги при загрузке страницы
window.onload = async function() {
await loadServices();
initCalendar();
};
// Загрузка услуг из API (только isactive=true)
async function loadServices() {
try {
const response = await fetch('/api/admin/services', {
headers: { 'Authorization': `Bearer ${token}` }
});
const data = await response.json();
services = data.filter(service => service.isactive);
const select = document.getElementById('serviceSelect');
select.innerHTML = '<option value="">Выберите услугу</option>';
for (let service of services) {
select.innerHTML += `<option value="${service.id}" data-duration="${service.durationminutes}">${service.name} (${service.durationminutes} мин) - ${service.price}₽</option>`;
}
} catch (error) {
alert('Ошибка загрузки услуг');
}
}
// Изменение услуги
//document.getElementById('serviceSelect').onchange = function()//