Refactor: Compact UI for product tags templates
Redesigned tag_form.html and tag_list.html with modern, compact layout: - Narrower card width, inline form elements, simplified controls - List-group layout instead of table for tag list - Streamlined JavaScript with auto-hiding messages 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -3,96 +3,56 @@
|
|||||||
{% block title %}{% if object %}Редактировать тег{% else %}Создать тег{% endif %}{% endblock %}
|
{% block title %}{% if object %}Редактировать тег{% else %}Создать тег{% endif %}{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="container mt-5">
|
<div class="container mt-4">
|
||||||
<div class="row justify-content-center">
|
<div class="row justify-content-center">
|
||||||
<div class="col-md-8">
|
<div class="col-sm-6 col-md-5 col-lg-4">
|
||||||
<div class="card">
|
<div class="card shadow-sm border-0">
|
||||||
<div class="card-header">
|
<div class="card-body p-4">
|
||||||
<h4 class="mb-0">
|
<h5 class="text-center mb-4">
|
||||||
{% if object %}
|
<i class="bi bi-tag{% if not object %}-fill{% endif %} text-primary"></i>
|
||||||
<i class="bi bi-pencil"></i> Редактировать тег
|
{% if object %}Редактировать{% else %}Новый тег{% endif %}
|
||||||
{% else %}
|
</h5>
|
||||||
<i class="bi bi-plus-circle"></i> Создать новый тег
|
|
||||||
{% endif %}
|
|
||||||
</h4>
|
|
||||||
</div>
|
|
||||||
<div class="card-body">
|
|
||||||
<form method="post">
|
<form method="post">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
|
|
||||||
<!-- Блок 1: Название -->
|
<div class="mb-3">
|
||||||
<div class="mb-4">
|
<div class="input-group">
|
||||||
<label for="id_name" class="form-label fw-bold fs-5">
|
<span class="input-group-text"><i class="bi bi-type"></i></span>
|
||||||
{{ form.name.label }}
|
{{ form.name }}
|
||||||
</label>
|
|
||||||
{{ form.name }}
|
|
||||||
{% if form.name.errors %}
|
|
||||||
<div class="text-danger mt-1">
|
|
||||||
{{ form.name.errors }}
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
{% if form.name.help_text %}
|
|
||||||
<div class="form-text">{{ form.name.help_text }}</div>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Блок 2: Slug -->
|
|
||||||
<div class="mb-4">
|
|
||||||
<label for="id_slug" class="form-label">
|
|
||||||
{{ form.slug.label }}
|
|
||||||
</label>
|
|
||||||
{{ form.slug }}
|
|
||||||
{% if form.slug.errors %}
|
|
||||||
<div class="text-danger mt-1">
|
|
||||||
{{ form.slug.errors }}
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
{% if form.slug.help_text %}
|
|
||||||
<div class="form-text">{{ form.slug.help_text }}</div>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Блок 3: Активность -->
|
|
||||||
<div class="mb-4">
|
|
||||||
<div class="form-check form-switch">
|
|
||||||
{{ form.is_active }}
|
|
||||||
<label class="form-check-label" for="id_is_active">
|
|
||||||
{{ form.is_active.label }}
|
|
||||||
</label>
|
|
||||||
</div>
|
</div>
|
||||||
{% if form.is_active.errors %}
|
{% if form.name.errors %}<small class="text-danger">{{ form.name.errors.0 }}</small>{% endif %}
|
||||||
<div class="text-danger mt-1">
|
|
||||||
{{ form.is_active.errors }}
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Кнопки действий -->
|
<div class="mb-3">
|
||||||
<div class="d-flex gap-2">
|
<div class="input-group">
|
||||||
|
<span class="input-group-text"><i class="bi bi-link-45deg"></i></span>
|
||||||
|
{{ form.slug }}
|
||||||
|
</div>
|
||||||
|
{% if form.slug.errors %}<small class="text-danger">{{ form.slug.errors.0 }}</small>{% endif %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-check form-switch mb-4">
|
||||||
|
{{ form.is_active }}
|
||||||
|
<label class="form-check-label small" for="id_is_active">Активен</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="d-grid gap-2">
|
||||||
<button type="submit" class="btn btn-primary">
|
<button type="submit" class="btn btn-primary">
|
||||||
<i class="bi bi-check-circle"></i>
|
<i class="bi bi-check2"></i> {% if object %}Сохранить{% else %}Создать{% endif %}
|
||||||
{% if object %}Сохранить изменения{% else %}Создать тег{% endif %}
|
|
||||||
</button>
|
</button>
|
||||||
<a href="{% url 'products:tag-list' %}" class="btn btn-outline-secondary">
|
<a href="{% url 'products:tag-list' %}" class="btn btn-light btn-sm">Отмена</a>
|
||||||
<i class="bi bi-x-circle"></i> Отмена
|
|
||||||
</a>
|
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Дополнительная информация при редактировании -->
|
{% if object %}
|
||||||
{% if object %}
|
<hr class="my-3">
|
||||||
<div class="card mt-3">
|
<small class="text-muted d-block text-center">
|
||||||
<div class="card-body">
|
<i class="bi bi-clock-history"></i> {{ object.updated_at|date:"d.m.Y H:i" }}
|
||||||
<h6 class="card-title">Дополнительная информация</h6>
|
</small>
|
||||||
<ul class="list-unstyled mb-0">
|
{% endif %}
|
||||||
<li><strong>Создан:</strong> {{ object.created_at|date:"d.m.Y H:i" }}</li>
|
|
||||||
<li><strong>Обновлен:</strong> {{ object.updated_at|date:"d.m.Y H:i" }}</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,164 +1,75 @@
|
|||||||
{% extends 'base.html' %}
|
{% extends 'base.html' %}
|
||||||
|
|
||||||
{% block title %}Теги товаров{% endblock %}
|
{% block title %}Теги{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="container mt-5">
|
<div class="container mt-4">
|
||||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
<div class="row justify-content-center">
|
||||||
<h2>Теги товаров</h2>
|
<div class="col-lg-8">
|
||||||
<a href="{% url 'products:tag-create' %}" class="btn btn-primary">
|
<!-- Заголовок и быстрое создание -->
|
||||||
<i class="bi bi-plus-circle"></i> Создать тег
|
<div class="d-flex align-items-center gap-3 mb-3">
|
||||||
</a>
|
<h5 class="mb-0"><i class="bi bi-tags text-primary"></i> Теги</h5>
|
||||||
</div>
|
<div class="input-group input-group-sm flex-grow-1" style="max-width: 300px;">
|
||||||
|
<input type="text" id="quick-tag-input" class="form-control" placeholder="Новый тег..." autocomplete="off">
|
||||||
<!-- Панель быстрого создания тега -->
|
<button class="btn btn-primary" id="quick-tag-btn" type="button"><i class="bi bi-plus"></i></button>
|
||||||
<div class="card mb-4">
|
</div>
|
||||||
<div class="card-body">
|
|
||||||
<h5 class="card-title mb-3">
|
|
||||||
<i class="bi bi-lightning-charge"></i> Быстрое создание тега
|
|
||||||
</h5>
|
|
||||||
<div class="input-group">
|
|
||||||
<input type="text" id="quick-tag-input" class="form-control form-control-lg"
|
|
||||||
placeholder="Введите название тега и нажмите Enter..."
|
|
||||||
autocomplete="off">
|
|
||||||
<button class="btn btn-success" id="quick-tag-btn" type="button">
|
|
||||||
<i class="bi bi-plus-circle"></i> Создать
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
<div id="quick-tag-message" class="mt-2"></div>
|
<div id="quick-tag-message"></div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Панель поиска и фильтров -->
|
<!-- Поиск и фильтр в одну строку -->
|
||||||
<div class="card mb-4">
|
<form method="get" class="d-flex gap-2 mb-3">
|
||||||
<div class="card-body">
|
<input type="text" class="form-control form-control-sm" name="search" value="{{ search_query }}" placeholder="Поиск...">
|
||||||
<form method="get" class="row g-3">
|
<select class="form-select form-select-sm" name="is_active" style="width: auto;" onchange="this.form.submit()">
|
||||||
<div class="col-md-6">
|
<option value="">Все</option>
|
||||||
<label for="search" class="form-label">Поиск</label>
|
<option value="1" {% if is_active_filter == '1' %}selected{% endif %}>Активные</option>
|
||||||
<input type="text" class="form-control" id="search" name="search"
|
<option value="0" {% if is_active_filter == '0' %}selected{% endif %}>Неактивные</option>
|
||||||
value="{{ search_query }}" placeholder="Поиск по названию или slug...">
|
</select>
|
||||||
</div>
|
<button type="submit" class="btn btn-outline-secondary btn-sm"><i class="bi bi-search"></i></button>
|
||||||
<div class="col-md-4">
|
|
||||||
<label for="is_active" class="form-label">Статус</label>
|
|
||||||
<select class="form-select" id="is_active" name="is_active">
|
|
||||||
<option value="">Все</option>
|
|
||||||
<option value="1" {% if is_active_filter == '1' %}selected{% endif %}>Активные</option>
|
|
||||||
<option value="0" {% if is_active_filter == '0' %}selected{% endif %}>Неактивные</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-2 d-flex align-items-end">
|
|
||||||
<button type="submit" class="btn btn-outline-secondary w-100">
|
|
||||||
<i class="bi bi-search"></i> Найти
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
</form>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Таблица с тегами -->
|
<!-- Список тегов -->
|
||||||
<div class="card">
|
|
||||||
<div class="card-body">
|
|
||||||
{% if tags %}
|
{% if tags %}
|
||||||
<div class="table-responsive">
|
<div class="list-group list-group-flush">
|
||||||
<table class="table table-striped table-hover">
|
{% for tag in tags %}
|
||||||
<thead class="table-dark">
|
<div class="list-group-item d-flex align-items-center py-2 px-3">
|
||||||
<tr>
|
<div class="form-check form-switch me-3 mb-0">
|
||||||
<th>Название</th>
|
<input class="form-check-input tag-status-switch" type="checkbox" data-tag-id="{{ tag.pk }}" {% if tag.is_active %}checked{% endif %}>
|
||||||
<th>Slug</th>
|
</div>
|
||||||
<th>Товары</th>
|
<div class="flex-grow-1">
|
||||||
<th>Комплекты</th>
|
<a href="{% url 'products:tag-detail' tag.pk %}" class="text-decoration-none fw-medium">{{ tag.name }}</a>
|
||||||
<th>Статус</th>
|
<small class="text-muted ms-2">{{ tag.slug }}</small>
|
||||||
<th>Действия</th>
|
</div>
|
||||||
</tr>
|
<div class="d-flex align-items-center gap-2">
|
||||||
</thead>
|
<span class="badge bg-secondary" title="Товаров">{{ tag.products_count }}</span>
|
||||||
<tbody>
|
<span class="badge bg-secondary" title="Комплектов">{{ tag.kits_count }}</span>
|
||||||
{% for tag in tags %}
|
<div class="btn-group btn-group-sm">
|
||||||
<tr>
|
<a href="{% url 'products:tag-update' tag.pk %}" class="btn btn-outline-secondary btn-sm py-0 px-1" title="Изменить"><i class="bi bi-pencil"></i></a>
|
||||||
<td>
|
<a href="{% url 'products:tag-delete' tag.pk %}" class="btn btn-outline-danger btn-sm py-0 px-1" title="Удалить"><i class="bi bi-trash"></i></a>
|
||||||
<a href="{% url 'products:tag-detail' tag.pk %}" class="text-decoration-none fw-semibold">
|
</div>
|
||||||
{{ tag.name }}
|
</div>
|
||||||
</a>
|
</div>
|
||||||
</td>
|
{% endfor %}
|
||||||
<td><code>{{ tag.slug }}</code></td>
|
|
||||||
<td>
|
|
||||||
<span class="badge bg-info">{{ tag.products_count }}</span>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<span class="badge bg-info">{{ tag.kits_count }}</span>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<div class="form-check form-switch" style="transform: scale(1.3); transform-origin: left;">
|
|
||||||
<input class="form-check-input tag-status-switch"
|
|
||||||
type="checkbox"
|
|
||||||
id="tag-status-{{ tag.pk }}"
|
|
||||||
data-tag-id="{{ tag.pk }}"
|
|
||||||
{% if tag.is_active %}checked{% endif %}>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<div class="btn-group btn-group-sm" role="group">
|
|
||||||
<a href="{% url 'products:tag-detail' tag.pk %}"
|
|
||||||
class="btn btn-outline-primary" title="Просмотр">
|
|
||||||
<i class="bi bi-eye"></i>
|
|
||||||
</a>
|
|
||||||
<a href="{% url 'products:tag-update' tag.pk %}"
|
|
||||||
class="btn btn-outline-warning" title="Изменить">
|
|
||||||
<i class="bi bi-pencil"></i>
|
|
||||||
</a>
|
|
||||||
<a href="{% url 'products:tag-delete' tag.pk %}"
|
|
||||||
class="btn btn-outline-danger" title="Удалить">
|
|
||||||
<i class="bi bi-trash"></i>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Пагинация -->
|
<!-- Пагинация -->
|
||||||
{% if is_paginated %}
|
{% if is_paginated %}
|
||||||
<nav aria-label="Pagination" class="mt-4">
|
<nav class="mt-3">
|
||||||
<ul class="pagination justify-content-center">
|
<ul class="pagination pagination-sm justify-content-center mb-0">
|
||||||
{% if page_obj.has_previous %}
|
{% if page_obj.has_previous %}
|
||||||
<li class="page-item">
|
<li class="page-item"><a class="page-link" href="?page={{ page_obj.previous_page_number }}{% if search_query %}&search={{ search_query }}{% endif %}{% if is_active_filter %}&is_active={{ is_active_filter }}{% endif %}">«</a></li>
|
||||||
<a class="page-link" href="?page=1{% if search_query %}&search={{ search_query }}{% endif %}{% if is_active_filter %}&is_active={{ is_active_filter }}{% endif %}">
|
|
||||||
Первая
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li class="page-item">
|
|
||||||
<a class="page-link" href="?page={{ page_obj.previous_page_number }}{% if search_query %}&search={{ search_query }}{% endif %}{% if is_active_filter %}&is_active={{ is_active_filter }}{% endif %}">
|
|
||||||
Назад
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
<li class="page-item active"><span class="page-link">{{ page_obj.number }}/{{ page_obj.paginator.num_pages }}</span></li>
|
||||||
<li class="page-item active">
|
|
||||||
<span class="page-link">
|
|
||||||
Страница {{ page_obj.number }} из {{ page_obj.paginator.num_pages }}
|
|
||||||
</span>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
{% if page_obj.has_next %}
|
{% if page_obj.has_next %}
|
||||||
<li class="page-item">
|
<li class="page-item"><a class="page-link" href="?page={{ page_obj.next_page_number }}{% if search_query %}&search={{ search_query }}{% endif %}{% if is_active_filter %}&is_active={{ is_active_filter }}{% endif %}">»</a></li>
|
||||||
<a class="page-link" href="?page={{ page_obj.next_page_number }}{% if search_query %}&search={{ search_query }}{% endif %}{% if is_active_filter %}&is_active={{ is_active_filter }}{% endif %}">
|
|
||||||
Вперед
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li class="page-item">
|
|
||||||
<a class="page-link" href="?page={{ page_obj.paginator.num_pages }}{% if search_query %}&search={{ search_query }}{% endif %}{% if is_active_filter %}&is_active={{ is_active_filter }}{% endif %}">
|
|
||||||
Последняя
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% else %}
|
{% else %}
|
||||||
<div class="alert alert-info" role="alert">
|
<div class="text-center text-muted py-4">
|
||||||
<i class="bi bi-info-circle"></i> Теги не найдены.
|
<i class="bi bi-tag fs-1 opacity-25"></i>
|
||||||
<a href="{% url 'products:tag-create' %}" class="alert-link">Создать первый тег</a>
|
<p class="mb-0 mt-2">Тегов пока нет</p>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
@@ -171,115 +82,61 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
const btn = document.getElementById('quick-tag-btn');
|
const btn = document.getElementById('quick-tag-btn');
|
||||||
const messageDiv = document.getElementById('quick-tag-message');
|
const messageDiv = document.getElementById('quick-tag-message');
|
||||||
|
|
||||||
// Автофокус на поле при загрузке страницы
|
|
||||||
input.focus();
|
|
||||||
|
|
||||||
function createTag() {
|
function createTag() {
|
||||||
const name = input.value.trim();
|
const name = input.value.trim();
|
||||||
|
if (!name) return;
|
||||||
|
|
||||||
if (!name) {
|
|
||||||
showMessage('Введите название тега', 'warning');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Блокируем кнопку и поле во время создания
|
|
||||||
btn.disabled = true;
|
btn.disabled = true;
|
||||||
input.disabled = true;
|
input.disabled = true;
|
||||||
btn.innerHTML = '<span class="spinner-border spinner-border-sm me-2"></span>Создание...';
|
btn.innerHTML = '<span class="spinner-border spinner-border-sm"></span>';
|
||||||
|
|
||||||
fetch('{% url "products:api-tag-create" %}', {
|
fetch('{% url "products:api-tag-create" %}', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: { 'Content-Type': 'application/json', 'X-CSRFToken': '{{ csrf_token }}' },
|
||||||
'Content-Type': 'application/json',
|
|
||||||
'X-CSRFToken': '{{ csrf_token }}'
|
|
||||||
},
|
|
||||||
body: JSON.stringify({name: name})
|
body: JSON.stringify({name: name})
|
||||||
})
|
})
|
||||||
.then(response => response.json())
|
.then(r => r.json())
|
||||||
.then(data => {
|
.then(data => {
|
||||||
if (data.success) {
|
if (data.success) {
|
||||||
showMessage(`✓ Тег "${data.tag.name}" успешно создан!`, 'success');
|
showMessage('Тег создан', 'success');
|
||||||
input.value = '';
|
setTimeout(() => window.location.reload(), 500);
|
||||||
|
|
||||||
// Перезагружаем страницу через 1 секунду для обновления списка
|
|
||||||
setTimeout(() => {
|
|
||||||
window.location.reload();
|
|
||||||
}, 1000);
|
|
||||||
} else {
|
} else {
|
||||||
showMessage('Ошибка: ' + data.error, 'danger');
|
showMessage(data.error, 'danger');
|
||||||
// Разблокируем поле и кнопку при ошибке
|
resetBtn();
|
||||||
btn.disabled = false;
|
|
||||||
input.disabled = false;
|
|
||||||
btn.innerHTML = '<i class="bi bi-plus-circle"></i> Создать';
|
|
||||||
input.focus();
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(() => { showMessage('Ошибка сети', 'danger'); resetBtn(); });
|
||||||
console.error('Error:', error);
|
}
|
||||||
showMessage('Ошибка сети при создании тега', 'danger');
|
|
||||||
// Разблокируем поле и кнопку при ошибке
|
function resetBtn() {
|
||||||
btn.disabled = false;
|
btn.disabled = false;
|
||||||
input.disabled = false;
|
input.disabled = false;
|
||||||
btn.innerHTML = '<i class="bi bi-plus-circle"></i> Создать';
|
btn.innerHTML = '<i class="bi bi-plus"></i>';
|
||||||
input.focus();
|
input.focus();
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function showMessage(text, type) {
|
function showMessage(text, type) {
|
||||||
messageDiv.innerHTML = `<div class="alert alert-${type} alert-dismissible fade show mb-0" role="alert">
|
messageDiv.innerHTML = `<div class="alert alert-${type} py-1 px-2 small mb-2">${text}</div>`;
|
||||||
${text}
|
setTimeout(() => messageDiv.innerHTML = '', 3000);
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
|
||||||
</div>`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Обработчик клика по кнопке
|
|
||||||
btn.addEventListener('click', createTag);
|
btn.addEventListener('click', createTag);
|
||||||
|
input.addEventListener('keypress', e => { if (e.key === 'Enter') { e.preventDefault(); createTag(); } });
|
||||||
|
|
||||||
// Обработчик нажатия Enter
|
// Toggle статуса
|
||||||
input.addEventListener('keypress', function(e) {
|
document.querySelectorAll('.tag-status-switch').forEach(toggle => {
|
||||||
if (e.key === 'Enter') {
|
toggle.addEventListener('click', async function(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
createTag();
|
const tagId = this.dataset.tagId;
|
||||||
}
|
try {
|
||||||
});
|
const response = await fetch(`/products/api/tags/${tagId}/toggle/`, {
|
||||||
});
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json', 'X-CSRFToken': '{{ csrf_token }}' }
|
||||||
// Обработчик переключения статуса тега
|
});
|
||||||
document.querySelectorAll('.tag-status-switch').forEach(toggle => {
|
const data = await response.json();
|
||||||
toggle.addEventListener('click', async function(e) {
|
if (data.success) this.checked = data.is_active;
|
||||||
e.preventDefault(); // Предотвращаем стандартное поведение checkbox
|
} catch (error) {}
|
||||||
|
});
|
||||||
const tagId = this.dataset.tagId;
|
|
||||||
const toggleSwitch = this;
|
|
||||||
const wasChecked = toggleSwitch.checked; // Сохраняем ТЕКУЩЕЕ состояние
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Отправляем AJAX запрос
|
|
||||||
const apiUrl = `/products/api/tags/${tagId}/toggle/`;
|
|
||||||
const response = await fetch(apiUrl, {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
'X-CSRFToken': '{{ csrf_token }}'
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const data = await response.json();
|
|
||||||
|
|
||||||
if (data.success) {
|
|
||||||
// Устанавливаем переключатель в НОВОЕ состояние согласно ответу сервера
|
|
||||||
toggleSwitch.checked = data.is_active;
|
|
||||||
|
|
||||||
// Показываем сообщение об успехе
|
|
||||||
showMessage(data.message, 'success');
|
|
||||||
} else {
|
|
||||||
// Переключатель остаётся в исходном состоянии (мы его не меняли)
|
|
||||||
showMessage(data.error || 'Ошибка при обновлении тега', 'danger');
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
// При ошибке сети - переключатель остаётся как был
|
|
||||||
showMessage('Ошибка сети: ' + error.message, 'danger');
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
Reference in New Issue
Block a user