cleanings
This commit is contained in:
@@ -0,0 +1,177 @@
|
||||
{% extends "admin/base_site.html" %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<style>
|
||||
#table-data-preview {
|
||||
max-height: 300px; /* Ограничиваем высоту предпросмотра */
|
||||
overflow-y: auto; /* Прокрутка по вертикали */
|
||||
overflow-x: auto; /* Прокрутка по горизонтали */
|
||||
}
|
||||
|
||||
#table-data-preview table {
|
||||
width: auto; /* Автоматическая ширина таблицы */
|
||||
table-layout: auto; /* Автоматическая ширина колонок */
|
||||
}
|
||||
|
||||
#table-data-preview th,
|
||||
#table-data-preview td {
|
||||
white-space: nowrap; /* Предотвращаем перенос текста */
|
||||
overflow: hidden; /* Скрываем текст, выходящий за границы ячейки */
|
||||
text-overflow: ellipsis; /* Добавляем многоточие для обрезанного текста */
|
||||
padding: 8px; /* Внутренний отступ */
|
||||
height: 40px; /* Фиксированная высота строк */
|
||||
}
|
||||
|
||||
#table-data-preview th {
|
||||
position: sticky; /* Фиксируем заголовки при прокрутке */
|
||||
top: 0; /* Располагаем заголовки вверху таблицы */
|
||||
background-color: #f8f9fa; /* Цвет фона заголовков */
|
||||
z-index: 1; /* Заголовки перекрывают содержимое */
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="container mt-4">
|
||||
<h2 class="text-center">Настройки подключения к БД</h2>
|
||||
<form id="connection-form" method="post">
|
||||
{% csrf_token %}
|
||||
<div class="form-group mb-3">
|
||||
<label for="db-name">Name</label>
|
||||
<input id="db-name" class="form-control" type="text" name="name" value="{{ original.name }}" required />
|
||||
</div>
|
||||
<div class="form-group mb-3">
|
||||
<label for="db-host">DB Host</label>
|
||||
<input id="db-host" class="form-control" type="text" name="host" value="{{ original.host }}" required />
|
||||
</div>
|
||||
<div class="form-group mb-3">
|
||||
<label for="db-port">DB Port</label>
|
||||
<input id="db-port" class="form-control" type="number" name="port" value="{{ original.port }}" required />
|
||||
</div>
|
||||
<div class="form-group mb-3">
|
||||
<label for="db-user">User</label>
|
||||
<input id="db-user" class="form-control" type="text" name="user" value="{{ original.user }}" required />
|
||||
</div>
|
||||
<div class="form-group mb-3">
|
||||
<label for="db-password">Password</label>
|
||||
<input id="db-password" class="form-control" type="password" name="password" value="{{ original.password }}" />
|
||||
</div>
|
||||
<div class="form-group mb-3">
|
||||
<label for="db-database">Database</label>
|
||||
<input id="db-database" class="form-control" type="text" name="database" value="{{ original.database }}" required />
|
||||
</div>
|
||||
<div class="form-group mb-3">
|
||||
<label for="table-selector">Таблицы</label>
|
||||
<select id="table-selector" class="form-select" name="table_name">
|
||||
{% if original.table_name %}
|
||||
<option value="{{ original.table_name }}" selected>{{ original.table_name }}</option>
|
||||
{% else %}
|
||||
<option value="">-- Выберите таблицу --</option>
|
||||
{% endif %}
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group mb-3">
|
||||
<label for="table-data-preview">Столбцы и данные</label>
|
||||
<div id="table-data-preview" class="table-responsive">
|
||||
<table class="table table-bordered">
|
||||
<thead id="table-header"></thead>
|
||||
<tbody id="table-body"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group mb-3">
|
||||
<label for="is-active">Активное подключение</label>
|
||||
<input id="is-active" class="form-check-input" type="checkbox" name="is_active" {% if original.is_active %}checked{% endif %} />
|
||||
</div>
|
||||
<div class="form-group text-center">
|
||||
<button class="btn btn-success" type="submit">Сохранить</button>
|
||||
<button class="btn btn-secondary" type="button" id="close-button">Закрыть</button>
|
||||
</div>
|
||||
</form>
|
||||
<hr>
|
||||
<div id="connection-status" class="mt-4"></div>
|
||||
<div class="text-center mt-3">
|
||||
<button id="test-connection" class="btn btn-primary" type="button">Проверить подключение</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if original.id %}
|
||||
<script>
|
||||
const dbId = "{{ original.id }}";
|
||||
</script>
|
||||
{% else %}
|
||||
<script>
|
||||
const dbId = null;
|
||||
document.getElementById("test-connection").style.display = "none";
|
||||
alert("Сохраните запись перед выполнением проверки подключения.");
|
||||
</script>
|
||||
{% endif %}
|
||||
|
||||
<script>
|
||||
// Закрыть окно
|
||||
document.getElementById("close-button").addEventListener("click", function() {
|
||||
window.history.back(); // Вернуться назад
|
||||
});
|
||||
|
||||
// Проверить подключение и загрузить таблицы
|
||||
document.getElementById("test-connection").addEventListener("click", function() {
|
||||
if (!dbId) {
|
||||
alert("ID подключения отсутствует.");
|
||||
return;
|
||||
}
|
||||
fetch(`/admin/antifroud/externaldbsettings/test-connection/?db_id=${dbId}`)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.status === "success") {
|
||||
document.getElementById("connection-status").innerHTML = `<div class="alert alert-success">${data.message}</div>`;
|
||||
fetch(`/admin/antifroud/externaldbsettings/fetch-tables/?db_id=${dbId}`)
|
||||
.then(response => response.json())
|
||||
.then(tableData => {
|
||||
if (tableData.status === "success") {
|
||||
const selector = document.getElementById("table-selector");
|
||||
selector.innerHTML = tableData.tables.map(table => `<option value="${table}">${table}</option>`).join("");
|
||||
} else {
|
||||
alert("Ошибка при загрузке таблиц: " + tableData.message);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
document.getElementById("connection-status").innerHTML = `<div class="alert alert-danger">${data.message}</div>`;
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
alert("Ошибка при проверке подключения.");
|
||||
console.error(error);
|
||||
});
|
||||
});
|
||||
|
||||
// При выборе таблицы загрузить столбцы и строки данных
|
||||
document.getElementById("table-selector").addEventListener("change", function () {
|
||||
const tableName = this.value;
|
||||
if (!tableName) {
|
||||
document.getElementById("table-header").innerHTML = "";
|
||||
document.getElementById("table-body").innerHTML = "";
|
||||
return;
|
||||
}
|
||||
|
||||
fetch(`/admin/antifroud/externaldbsettings/fetch-table-data/?db_id=${dbId}&table_name=${tableName}`)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.status === "success") {
|
||||
const headerRow = data.columns.map(col => `<th>${col}</th>`).join("");
|
||||
document.getElementById("table-header").innerHTML = `<tr>${headerRow}</tr>`;
|
||||
|
||||
const rows = data.rows.map(row => {
|
||||
const cells = row.map(cell => `<td>${cell}</td>`).join("");
|
||||
return `<tr>${cells}</tr>`;
|
||||
}).join("");
|
||||
document.getElementById("table-body").innerHTML = rows;
|
||||
} else {
|
||||
alert("Ошибка при загрузке данных таблицы: " + data.message);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
alert("Ошибка при загрузке данных таблицы.");
|
||||
console.error(error);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
97
antifroud/templates/antifroud/admin/import_hotels.html
Normal file
97
antifroud/templates/antifroud/admin/import_hotels.html
Normal file
@@ -0,0 +1,97 @@
|
||||
{% extends "admin/change_list.html" %}
|
||||
{% block content %}
|
||||
|
||||
|
||||
<!-- Кнопка импорта -->
|
||||
<div class="form-group mb-3">
|
||||
<button type="submit" class="btn btn-primary" form="importHotelsForm">
|
||||
Импортировать выбранные отели
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Действия админки -->
|
||||
{{ block.super }}
|
||||
|
||||
<!-- Уведомление -->
|
||||
<div id="notification" class="alert alert-info d-none" role="alert">
|
||||
Здесь появятся уведомления.
|
||||
</div>
|
||||
|
||||
<!-- Форма для импорта отелей -->
|
||||
<form id="importHotelsForm" method="POST">
|
||||
{% csrf_token %}
|
||||
{{ form.as_p }} <!-- Отображаем форму -->
|
||||
</form>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block extrahead %}
|
||||
{{ block.super }}
|
||||
<!-- Подключаем Bootstrap 4 -->
|
||||
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" rel="stylesheet">
|
||||
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
|
||||
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.bundle.min.js"></script>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const importButton = document.querySelector("button[type='submit']");
|
||||
const notificationElement = document.getElementById('notification');
|
||||
|
||||
// Слушатель для отправки формы
|
||||
importButton.addEventListener('click', function(e) {
|
||||
e.preventDefault(); // предотвращаем стандартное поведение кнопки
|
||||
|
||||
// Извлекаем выбранные отели
|
||||
const checkboxes = document.querySelectorAll('input[name="hotels"]:checked');
|
||||
const selectedHotels = [];
|
||||
console.log("Чекбоксы:", checkboxes); // Консольная отладка
|
||||
|
||||
checkboxes.forEach(function(checkbox) {
|
||||
selectedHotels.push(checkbox.value);
|
||||
console.log("Выбранный отель:", checkbox.value); // Консольная отладка
|
||||
});
|
||||
|
||||
// Если выбраны отели
|
||||
if (selectedHotels.length > 0) {
|
||||
// Преобразуем CSRF токен
|
||||
const csrfToken = document.querySelector('[name=csrfmiddlewaretoken]').value;
|
||||
console.log("CSRF токен:", csrfToken); // Консольная отладка
|
||||
|
||||
// Отправляем данные на сервер
|
||||
fetch('/import_hotels/', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRFToken': csrfToken,
|
||||
},
|
||||
body: JSON.stringify({ hotels: selectedHotels })
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
console.log("Ответ от сервера:", data); // Консольная отладка
|
||||
// Показать успешное уведомление
|
||||
notificationElement.classList.remove('d-none');
|
||||
notificationElement.classList.add('alert-success');
|
||||
notificationElement.textContent = data.message || "Отели успешно импортированы!";
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("Ошибка при импорте:", error); // Консольная отладка
|
||||
// Показать ошибку
|
||||
notificationElement.classList.remove('d-none');
|
||||
notificationElement.classList.add('alert-danger');
|
||||
notificationElement.textContent = "Произошла ошибка при импорте отелей.";
|
||||
})
|
||||
.finally(() => {
|
||||
// Сброс кнопки
|
||||
importButton.disabled = false;
|
||||
importButton.textContent = 'Импортировать выбранные отели';
|
||||
});
|
||||
} else {
|
||||
console.log("Не выбраны отели"); // Консольная отладка
|
||||
notificationElement.classList.remove('d-none');
|
||||
notificationElement.classList.add('alert-warning');
|
||||
notificationElement.textContent = "Пожалуйста, выберите хотя бы один отель для импорта.";
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,33 @@
|
||||
{% extends "admin/base_site.html" %}
|
||||
{% load i18n static %}
|
||||
|
||||
{% block title %}Редактирование отеля{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container-fluid">
|
||||
<h3 class="text-dark mb-4">Редактирование отеля</h3>
|
||||
|
||||
<form method="post" action="{% url 'admin:save_edited_hotel' hotel.id %}">
|
||||
{% csrf_token %}
|
||||
<div class="form-group mb-3">
|
||||
<label for="display_name" class="form-label">Отображаемое имя</label>
|
||||
<input class="form-control" type="text" id="display_name" name="display_name" value="{{ hotel.display_name }}" required>
|
||||
</div>
|
||||
<div class="form-group mb-3">
|
||||
<label for="original_name" class="form-label">Оригинальное имя</label>
|
||||
<input class="form-control" type="text" id="original_name" name="original_name" value="{{ hotel.name }}" required>
|
||||
</div>
|
||||
<div class="form-group mb-3">
|
||||
<label for="imported" class="form-label">Импортирован</label>
|
||||
<select class="form-select" id="imported" name="imported">
|
||||
<option value="True" {% if hotel.imported %} selected {% endif %}>Да</option>
|
||||
<option value="False" {% if not hotel.imported %} selected {% endif %}>Нет</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group mb-3">
|
||||
<button type="submit" class="btn btn-primary">Сохранить изменения</button>
|
||||
<a href="{% url 'admin:hotel_list' %}" class="btn btn-secondary">Назад</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{% endblock %}
|
||||
143
antifroud/templates/antifroud/admin/imported_hotels.html
Normal file
143
antifroud/templates/antifroud/admin/imported_hotels.html
Normal file
@@ -0,0 +1,143 @@
|
||||
{% extends "admin/change_list.html" %}
|
||||
{% block content %}
|
||||
<!-- Кнопка импорта -->
|
||||
<div class="form-group mb-3">
|
||||
<button type="button" class="btn btn-primary" id="importHotelsButton">
|
||||
Импортировать выбранные отели
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Уведомление -->
|
||||
<div id="notification" class="alert alert-info d-none" role="alert">
|
||||
Здесь появятся уведомления.
|
||||
</div>
|
||||
|
||||
<!-- Действия админки -->
|
||||
{{ block.super }}
|
||||
|
||||
<!-- Список отелей для выбора в виде таблицы -->
|
||||
<form id="importHotelsForm" method="POST">
|
||||
{% csrf_token %}
|
||||
|
||||
<div class="table-responsive">
|
||||
<table class="table table-bordered">
|
||||
<thead class="thead-dark">
|
||||
<tr>
|
||||
<!-- Чекбокс для выбора всех отелей -->
|
||||
<th><input type="checkbox" id="select-all" /></th>
|
||||
<th>Внешний ID</th>
|
||||
<th>Отображаемое имя</th>
|
||||
<th>Имя отеля</th>
|
||||
<th>Дата создания</th>
|
||||
<th>Дата обновления</th>
|
||||
<th>Импортирован в основную базу</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for hotel in imported_hotels %}
|
||||
<tr>
|
||||
<td>
|
||||
<input type="checkbox" name="hotels" value="{{ hotel.id }}" id="hotel{{ hotel.id }}" class="select-row" />
|
||||
</td>
|
||||
<td>{{ hotel.external_id }}</td>
|
||||
<td>{{ hotel.display_name }}</td>
|
||||
<td>{{ hotel.name }}</td>
|
||||
<td>{{ hotel.creation_date }}</td>
|
||||
<td>{{ hotel.updated_at }}</td>
|
||||
<td>{{ hotel.imported_to_main_db }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- Здесь вы можете добавить скрытые поля или другие элементы формы, если они нужны -->
|
||||
</form>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block extrahead %}
|
||||
{{ block.super }}
|
||||
<!-- Подключаем Bootstrap 4 -->
|
||||
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" rel="stylesheet">
|
||||
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
|
||||
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.bundle.min.js"></script>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Обработчик для выбора всех чекбоксов
|
||||
const selectAllCheckbox = document.getElementById('select-all');
|
||||
selectAllCheckbox.addEventListener('change', function() {
|
||||
const checkboxes = document.querySelectorAll(".select-row");
|
||||
checkboxes.forEach(function(checkbox) {
|
||||
checkbox.checked = selectAllCheckbox.checked;
|
||||
});
|
||||
});
|
||||
|
||||
// Кнопка импорта
|
||||
const importButton = document.getElementById('importHotelsButton');
|
||||
const notificationElement = document.getElementById('notification');
|
||||
|
||||
importButton.addEventListener('click', function(e) {
|
||||
e.preventDefault(); // предотвращаем стандартное поведение кнопки
|
||||
|
||||
// Даем время DOM полностью загрузиться
|
||||
setTimeout(function() {
|
||||
const checkboxes = document.querySelectorAll('input[name="hotels"]:checked');
|
||||
const selectedHotels = [];
|
||||
|
||||
console.log("Чекбоксы:", checkboxes); // Отладка: выводим все выбранные чекбоксы
|
||||
|
||||
checkboxes.forEach(function(checkbox) {
|
||||
selectedHotels.push(checkbox.value);
|
||||
console.log("Выбранный отель:", checkbox.value); // Отладка: выводим ID выбранного отеля
|
||||
});
|
||||
|
||||
if (selectedHotels.length > 0) {
|
||||
const csrfToken = document.querySelector('[name=csrfmiddlewaretoken]').value;
|
||||
console.log("CSRF токен:", csrfToken);
|
||||
|
||||
importButton.disabled = true;
|
||||
importButton.textContent = 'Импортируем...';
|
||||
|
||||
// Отправка выбранных отелей на сервер через fetch
|
||||
fetch('/import_hotels/', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRFToken': csrfToken,
|
||||
},
|
||||
body: JSON.stringify({ hotels: selectedHotels })
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
console.log("Ответ сервера:", data);
|
||||
notificationElement.classList.remove('d-none');
|
||||
notificationElement.classList.add('alert-success');
|
||||
notificationElement.textContent = "Отели успешно импортированы!";
|
||||
checkboxes.forEach(checkbox => checkbox.checked = false); // Снимаем выделение с чекбоксов
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("Ошибка при импорте:", error);
|
||||
notificationElement.classList.remove('d-none');
|
||||
notificationElement.classList.add('alert-danger');
|
||||
notificationElement.textContent = "Произошла ошибка при импорте отелей.";
|
||||
})
|
||||
.finally(() => {
|
||||
importButton.disabled = false;
|
||||
importButton.textContent = 'Импортировать выбранные отели';
|
||||
});
|
||||
} else {
|
||||
console.log("Не выбраны отели");
|
||||
notificationElement.classList.remove('d-none');
|
||||
notificationElement.classList.add('alert-warning');
|
||||
notificationElement.textContent = "Пожалуйста, выберите хотя бы один отель для импорта.";
|
||||
}
|
||||
}, 100); // Задержка 100ms, чтобы дождаться рендеринга всех элементов
|
||||
});
|
||||
});
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const checkboxes = document.querySelectorAll('input[name="hotels"]');
|
||||
console.log("Чекбоксы на странице:", checkboxes); // Проверим, есть ли чекбоксы
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user