Files
cleaning-company/public/admin-services.html
Владимир ae5ab2554b commit 12.01
2026-01-12 14:25:15 +00:00

285 lines
11 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!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: #2c3e50; color: white; padding: 20px 50px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1); position: sticky; top: 0;
}
.header-content {
max-width: 1200px; margin: 0 auto;
display: flex; justify-content: space-between; align-items: center;
}
.logo { font-size: 24px; font-weight: bold; }
.header-nav { display: flex; gap: 20px; }
.btn {
padding: 12px 25px; border: none; border-radius: 25px;
cursor: pointer; font-size: 16px; text-decoration: none;
display: inline-block; transition: all 0.3s; color: white;
}
.btn-primary { background: #667eea; }
.btn-primary:hover { background: #5a67d8; }
.btn-secondary { background: #6c757d; }
.btn-secondary:hover { background: #5a6268; }
/* Контейнер */
.container { max-width: 1200px; margin: 40px auto; padding: 0 20px; }
h1 { text-align: center; color: #333; margin-bottom: 40px; font-size: 32px; }
/* Форма добавления */
.add-service-form {
background: white; padding: 40px; border-radius: 20px;
box-shadow: 0 20px 40px rgba(0,0,0,0.1); margin-bottom: 40px;
}
.form-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 20px; }
label { display: block; margin-bottom: 8px; font-weight: bold; color: #555; }
input, textarea {
width: 100%; padding: 15px; border: 2px solid #e9ecef;
border-radius: 10px; font-size: 16px; transition: border-color 0.3s;
}
input:focus, textarea:focus { outline: none; border-color: #667eea; }
textarea { resize: vertical; min-height: 100px; }
/* Таблица услуг */
.services-table {
background: white; border-radius: 20px;
box-shadow: 0 20px 40px rgba(0,0,0,0.1); overflow: hidden;
}
table { width: 100%; border-collapse: collapse; }
th, td { padding: 20px; text-align: left; border-bottom: 1px solid #e9ecef; }
th { background: #667eea; color: white; font-weight: bold; }
tr:hover { background: #f8f9fa; }
/* Статус */
.status-badge { padding: 6px 12px; border-radius: 15px; font-size: 14px; font-weight: bold; }
.status-active { background: #d4edda; color: #155724; }
.status-inactive { background: #f8d7da; color: #721c24; }
/* Кнопки действий */
.action-buttons { display: flex; gap: 10px; flex-wrap: wrap; }
.btn-small {
padding: 8px 16px; font-size: 14px; border-radius: 15px;
text-decoration: none; border: none; cursor: pointer;
}
.btn-edit { background: #ffc107; color: #212529; }
.btn-edit:hover { background: #e0a800; }
.btn-toggle { background: #17a2b8; color: white; }
.btn-toggle:hover { background: #138496; }
.btn-delete { background: #dc3545; color: white; }
.btn-delete:hover { background: #c82333; }
/* Модальное окно */
.modal {
display: none; position: fixed; top: 0; left: 0;
width: 100%; height: 100%; background: rgba(0,0,0,0.5); z-index: 1000;
}
.modal-content {
background: white; margin: 5% auto; padding: 40px;
border-radius: 20px; max-width: 600px; width: 90%; position: relative;
}
.close {
position: absolute; top: 15px; right: 20px; font-size: 28px;
cursor: pointer; color: #999;
}
.close:hover { color: #333; }
@media (max-width: 768px) {
.form-grid { grid-template-columns: 1fr; }
.action-buttons { flex-direction: column; }
th, td { padding: 15px 10px; font-size: 14px; }
}
</style>
</head>
<body>
<!-- Хедер -->
<header>
<div class="header-content">
<div class="logo">🧹 КлинСервис - Админка</div>
<div class="header-nav">
<a href="admin-bookings.html" class="btn btn-secondary">Брони</a>
<a href="index.html" class="btn btn-primary">На главную</a>
<button class="btn btn-secondary" onclick="logout()">Выйти</button>
</div>
</div>
</header>
<div class="container">
<h1>⚙️ Управление услугами</h1>
<!-- Форма добавления услуги -->
<div class="add-service-form">
<h3 style="margin-bottom: 25px; color: #333;"> Добавить новую услугу</h3>
<form id="addServiceForm" onsubmit="addService(event)" class="form-grid">
<div>
<label>Название *</label>
<input type="text" id="serviceName" required placeholder="Генеральная уборка">
</div>
<div>
<label>Цена (₽) *</label>
<input type="number" id="servicePrice" required min="0" placeholder="5000">
</div>
<div>
<label>Длительность (минуты) *</label>
<input type="number" id="serviceDuration" required min="30" placeholder="120">
</div>
<div style="grid-column: span 2;">
<label>Описание</label>
<textarea id="serviceDescription" placeholder="Полная уборка с мойкой окон..."></textarea>
</div>
<div style="grid-column: span 2;">
<button type="submit" class="btn btn-primary" style="width: 200px; padding: 15px 30px;">
Создать услугу
</button>
</div>
</form>
</div>
<!-- Таблица услуг -->
<div class="services-table">
<table>
<thead>
<tr>
<th>ID</th>
<th>Название</th>
<th>Описание</th>
<th>Длительность</th>
<th>Цена</th>
<th>Статус</th>
<th>Действия</th>
</tr>
</thead>
<tbody id="servicesTable">
<tr>
<td colspan="7" style="text-align: center; padding: 40px; color: #666;">
Загрузка услуг...
</td>
</tr>
</tbody>
</table>
</div>
</div>
<!-- Модальное окно удаления -->
<div id="deleteModal" class="modal">
<div class="modal-content">
<span class="close" onclick="closeModal()">&times;</span>
<h3>Удалить услугу?</h3>
<p>Услуга <strong id="deleteServiceName"></strong> будет удалена навсегда.</p>
<div style="display: flex; gap: 15px; margin-top: 30px;">
<button class="btn btn-secondary" onclick="closeModal()" style="flex: 1;">Отмена</button>
<button class="btn btn-delete" onclick="confirmDelete()" style="flex: 1;">Удалить</button>
</div>
</div>
</div>
<script>
const token = localStorage.getItem('token');
if (!token) {
window.location.href = 'register-login.html';
}
window.onload = loadServices;
async function loadServices() {
try {
const res = await fetch('/api/admin/services', {
headers: { 'Authorization': `Bearer ${token}` }
});
const services = await res.json();
const list = document.getElementById('services-list');
services.forEach(s => {
list.innerHTML += `
<div>
<p><strong>${s.name}</strong> — ${s.price}₽ — ${s.is_active ? 'Активна' : 'Неактивна'}</p>
<button onclick="editService(${s.id})">Редактировать</button>
<button onclick="toggleService(${s.id}, ${s.is_active})">${s.is_active ? '❌ Деактивировать' : '✅ Активировать'}</button>
<button onclick="deleteService(${s.id})">🗑️ Удалить</button>
</div>
`;
});
} catch (err) {
alert('Ошибка загрузки услуг');
}
}
async function addService(event) {
event.preventDefault();
const formData = {
name: document.getElementById('serviceName').value,
description: document.getElementById('serviceDescription').value,
duration_minutes: parseInt(document.getElementById('serviceDuration').value),
price: parseFloat(document.getElementById('servicePrice').value),
is_active: true
};
try {
const res = await fetch('/api/admin/services', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
},
body: JSON.stringify(formData)
});
if (res.ok) {
alert('Услуга добавлена');
document.getElementById('addServiceForm').reset();
window.location.reload();
}
} catch (err) {
alert('Ошибка добавления');
}
}
async function toggleService(id, isActive) {
try {
const res = await fetch(`/api/admin/services/${id}`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
},
body: JSON.stringify({ is_active: !isActive })
});
if (res.ok) {
alert(`Услуга ${!isActive ? 'активирована' : 'деактивирована'}`);
window.location.reload();
}
} catch (err) {
alert('Ошибка');
}
}
async function deleteService(id) {
if (confirm('Удалить услугу?')) {
try {
const res = await fetch(`/api/admin/services/${id}`, {
method: 'DELETE',
headers: { 'Authorization': `Bearer ${token}` }
});
if (res.ok) {
alert('Услуга удалена');
window.location.reload();
}
} catch (err) {
alert('Ошибка');
}
}
}
</script>
</body>
</html>