Files
2025-09-25 20:49:02 +03:00

422 lines
21 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.4.0/css/all.min.css">
<style>
.form-container {
max-width: 800px;
margin: 0 auto;
}
.preview-image {
max-height: 400px;
object-fit: contain;
}
.required:after {
content: " *";
color: red;
}
.form-label {
font-weight: 500;
}
.toast-container {
z-index: 1055; /* Выше чем у других элементов */
}
</style>
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
<div class="container-fluid">
<a class="navbar-brand" href="#">Редактирование события</a>
<div class="navbar-nav ms-auto">
<a class="nav-link" href="#" id="back-link">
<i class="fas fa-arrow-left me-1"></i> Назад к списку
</a>
</div>
</div>
</nav>
<div class="container py-4">
<div class="d-flex justify-content-between align-items-center mb-4">
<h2 id="form-title">{{ 'Редактирование события' if event_id else 'Добавление нового события' }}</h2>
<a href="#" id="back-button" class="btn btn-outline-secondary">
<i class="fas fa-arrow-left me-1"></i> Назад
</a>
</div>
<div class="card form-container">
<div class="card-body">
<form id="event-form">
<input type="hidden" id="event-id" value="{{ event_id if event_id }}">
<div class="row mb-3">
<div class="col-md-6">
<label for="number" class="form-label required">Номер события</label>
<input type="number" class="form-control" id="number" required>
</div>
<div class="col-md-6">
<div class="form-group">
<label class="form-label">Local ID</label>
<div class="form-control-plaintext" id="event-local-id">
{{ event_id if event_id else 'Новый' }}
</div>
</div>
</div>
<div class="col-md-6">
<label for="name" class="form-label required">Название события</label>
<input type="text" class="form-control" id="name" required>
</div>
</div>
<div class="row mb-3">
<div class="col-md-6">
<label for="unit_name" class="form-label">Площадка</label>
<input type="text" class="form-control" id="unit_name">
</div>
<div class="col-md-6">
<label for="id_event" class="form-label">Серверный ID</label>
<input type="number" class="form-control" id="id_event">
</div>
</div>
<div class="mb-3">
<label for="about" class="form-label">Описание</label>
<textarea class="form-control" id="about" rows="4"></textarea>
</div>
<div class="row mb-3">
<div class="col-md-6">
<label for="about_social_picture" class="form-label">URL изображения</label>
<input type="url" class="form-control" id="about_social_picture">
</div>
<div class="col-md-6">
<label for="tags" class="form-label">Тэги</label>
<input type="text" class="form-control" id="tags">
</div>
</div>
<!-- Preview изображения -->
<div class="mb-3 text-center" id="image-preview-container" style="display: none;">
<img id="image-preview" class="preview-image img-thumbnail">
</div>
<div class="row mb-3">
<div class="col-md-4">
<label for="added" class="form-label">Дата добавления</label>
<input type="datetime-local" class="form-control" id="added">
</div>
<div class="col-md-4">
<label for="modified" class="form-label">Дата изменения</label>
<input type="datetime-local" class="form-control" id="modified">
</div>
<div class="col-md-4">
<label for="announcement_link" class="form-label">Ссылка на анонс</label>
<input type="text" class="form-control" id="announcement_link">
</div>
</div>
<div class="row mb-3">
<div class="col-md-3">
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" id="is_canceled">
<label class="form-check-label" for="is_canceled">Отменено</label>
</div>
</div>
<div class="col-md-3">
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" id="accepted">
<label class="form-check-label" for="accepted">Принято</label>
</div>
</div>
<div class="col-md-3">
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" id="denied">
<label class="form-check-label" for="denied">Отказано</label>
</div>
</div>
<div class="col-md-3">
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" id="is_visible">
<label class="form-check-label" for="is_visible">Видно</label>
</div>
</div>
</div>
<div class="row mb-3">
<div class="col-md-4">
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" id="marked_to_publication">
<label class="form-check-label" for="marked_to_publication">Отмечено для публикации</label>
</div>
</div>
<div class="col-md-4">
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" id="is_posted_tg">
<label class="form-check-label" for="is_posted_tg">Опубликовано в TG</label>
</div>
</div>
<div class="col-md-4">
<label for="tg_message_id" class="form-label">ID сообщения в TG</label>
<input type="number" class="form-control" id="tg_message_id">
</div>
</div>
<div class="row mb-3">
<div class="col-md-6">
<label for="tg_posted_date" class="form-label">Дата публикации в TG</label>
<input type="datetime-local" class="form-control" id="tg_posted_date">
</div>
</div>
<div class="d-flex justify-content-between">
<button type="button" class="btn btn-secondary" id="cancel-btn">
<i class="fas fa-times me-1"></i> Отмена
</button>
<button type="submit" class="btn btn-primary">
<i class="fas fa-save me-1"></i> Сохранить
</button>
</div>
</form>
</div>
</div>
<!-- Контейнер для уведомлений -->
<div class="toast-container position-fixed top-0 end-0 p-3">
<div id="success-toast" class="toast align-items-center text-white bg-success border-0" role="alert" aria-live="assertive" aria-atomic="true">
<div class="d-flex">
<div class="toast-body">
<i class="fas fa-check-circle me-2"></i> Событие успешно сохранено!
</div>
<button type="button" class="btn-close btn-close-white me-2 m-auto" data-bs-dismiss="toast" aria-label="Close"></button>
</div>
</div>
</div>
</div>
<!-- Сообщение о процессе выполнения -->
<div id="processing-message" class="alert alert-info position-fixed top-50 start-50 translate-middle" style="display: none; z-index: 1050;">
<div class="d-flex align-items-center">
<div class="spinner-border spinner-border-sm me-2" role="status">
<span class="visually-hidden">Загрузка...</span>
</div>
<span id="processing-text">Обработка...</span>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
<script>
const PREFIX = "{{ g.prefix }}";
const EVENT_ID = {{ event_id if event_id else 'null' }};
// Инициализация toast
const successToast = new bootstrap.Toast(document.getElementById('success-toast'));
document.addEventListener('DOMContentLoaded', () => {
// Загрузка данных события, если редактируем существующее
if (EVENT_ID) {
loadEventData(EVENT_ID);
}
// Обработчик отправки формы
document.getElementById('event-form').addEventListener('submit', (e) => {
e.preventDefault();
saveEvent();
});
// Обработчики кнопок отмены и назад
const cancelHandler = () => {
if (EVENT_ID) {
window.location.href = `${PREFIX}/?selected_event=${EVENT_ID}&tab=events`;
} else {
window.location.href = `${PREFIX}/?tab=events`;
}
};
document.getElementById('cancel-btn').addEventListener('click', cancelHandler);
document.getElementById('back-button').addEventListener('click', cancelHandler);
document.getElementById('back-link').addEventListener('click', cancelHandler);
// Предпросмотр изображения
document.getElementById('about_social_picture').addEventListener('change', function() {
const url = this.value.trim();
const previewContainer = document.getElementById('image-preview-container');
const previewImage = document.getElementById('image-preview');
if (url) {
previewImage.src = `${PREFIX}/image_proxy?url=${encodeURIComponent(url)}`;
previewContainer.style.display = 'block';
} else {
previewContainer.style.display = 'none';
}
});
});
// Загрузка данных события
async function loadEventData(eventId) {
showProcessingMessage("Загрузка данных события...");
try {
const response = await fetch(`${PREFIX}/api/events/${eventId}`);
if (!response.ok) {
throw new Error('Событие не найдено');
}
const event = await response.json();
// Заполняем форму данными
document.getElementById('number').value = event.number || '';
document.getElementById('name').value = event.name || '';
document.getElementById('unit_name').value = event.unit_name || '';
document.getElementById('id_event').value = event.id_event || '';
document.getElementById('about').value = event.about || '';
document.getElementById('about_social_picture').value = event.about_social_picture || '';
document.getElementById('tags').value = event.tags || '';
document.getElementById('announcement_link').value = event.announcement_link || '';
document.getElementById('tg_message_id').value = event.tg_message_id || '';
document.getElementById('event-local-id').textContent = event.id;
// Заполняем чекбоксы
document.getElementById('is_canceled').checked = event.is_canceled || false;
document.getElementById('accepted').checked = event.accepted || false;
document.getElementById('denied').checked = event.denied || false;
document.getElementById('is_visible').checked = event.is_visible || false;
document.getElementById('marked_to_publication').checked = event.marked_to_publication || false;
document.getElementById('is_posted_tg').checked = event.is_posted_tg || false;
// Заполняем даты
if (event.added) {
const addedDate = new Date(event.added);
// document.getElementById('added').value = addedDate.toISOString().slice(0, 16);
document.getElementById('added').value = convertUTCToLocal(event.added);
}
if (event.modified) {
const modifiedDate = new Date(event.modified);
// document.getElementById('modified').value = modifiedDate.toISOString().slice(0, 16);
document.getElementById('modified').value = convertUTCToLocal(event.modified);
}
if (event.tg_posted_date) {
const tgPostedDate = new Date(event.tg_posted_date);
// document.getElementById('tg_posted_date').value = tgPostedDate.toISOString().slice(0, 16);
document.getElementById('tg_posted_date').value = convertUTCToLocal(event.tg_posted_date);
}
// Показываем изображение, если есть
if (event.about_social_picture) {
document.getElementById('image-preview').src =
`${PREFIX}/image_proxy?url=${encodeURIComponent(event.about_social_picture)}`;
document.getElementById('image-preview-container').style.display = 'block';
}
} catch (error) {
alert(`Ошибка загрузки данных: ${error.message}`);
} finally {
hideProcessingMessage();
}
}
// Сохранение события
async function saveEvent() {
showProcessingMessage("Сохранение события...");
const formData = {
number: document.getElementById('number').value,
name: document.getElementById('name').value,
unit_name: document.getElementById('unit_name').value,
id_event: document.getElementById('id_event').value,
about: document.getElementById('about').value,
about_social_picture: document.getElementById('about_social_picture').value,
tags: document.getElementById('tags').value,
announcement_link: document.getElementById('announcement_link').value,
tg_message_id: document.getElementById('tg_message_id').value,
is_canceled: document.getElementById('is_canceled').checked,
accepted: document.getElementById('accepted').checked,
denied: document.getElementById('denied').checked,
is_visible: document.getElementById('is_visible').checked,
marked_to_publication: document.getElementById('marked_to_publication').checked,
is_posted_tg: document.getElementById('is_posted_tg').checked,
added: convertLocalToUTC(document.getElementById('added').value),
modified: convertLocalToUTC(document.getElementById('modified').value),
tg_posted_date: convertLocalToUTC(document.getElementById('tg_posted_date').value)
};
try {
let response;
if (EVENT_ID) {
// Обновление существующего события
response = await fetch(`${PREFIX}/api/events/${EVENT_ID}`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
'X-Requested-With': 'XMLHttpRequest'
},
body: JSON.stringify(formData)
});
} else {
// Создание нового события
response = await fetch(`${PREFIX}/api/events`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Requested-With': 'XMLHttpRequest'
},
body: JSON.stringify(formData)
});
}
const result = await response.json();
if (result.success) {
// Показываем уведомление об успехе
successToast.show();
// Ждем 1.5 секунды перед перенаправлением
setTimeout(() => {
window.location.href = `${PREFIX}/?selected_event=${result.event_id || EVENT_ID}&tab=events`;
}, 1500);
} else {
throw new Error(result.error || 'Неизвестная ошибка');
}
} catch (error) {
alert(`Ошибка сохранения: ${error.message}`);
} finally {
hideProcessingMessage();
}
}
// добавим функцию преобразования UTC в локальное время
function convertUTCToLocal(utcString) {
if (!utcString) return '';
const date = new Date(utcString);
const localDate = new Date(date.getTime() - date.getTimezoneOffset() * 60000);
return localDate.toISOString().slice(0, 16);
}
// добавим функцию преобразования локального времени в UTC
function convertLocalToUTC(localString) {
if (!localString) return null;
const date = new Date(localString);
const utcDate = new Date(date.getTime() + date.getTimezoneOffset() * 60000);
return utcDate.toISOString().slice(0, 19).replace('T', ' ');
}
// Функции для показа/скрытия сообщения о обработке
function showProcessingMessage(message) {
const processingElement = document.getElementById('processing-message');
const processingText = document.getElementById('processing-text');
processingText.textContent = message;
processingElement.style.display = 'flex';
}
function hideProcessingMessage() {
const processingElement = document.getElementById('processing-message');
processingElement.style.display = 'none';
}
</script>
</body>
</html>