Обновили шапку и вывод всехтоваров. Добавили фильтры
This commit is contained in:
@@ -0,0 +1,39 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Удалить клиента{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<h1>Удалить клиента</h1>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<p>Вы уверены, что хотите удалить следующего клиента?</p>
|
||||
|
||||
<div class="alert alert-warning">
|
||||
<h5>{{ customer.full_name }}</h5>
|
||||
<p>
|
||||
<strong>Email:</strong> {{ customer.email }}<br>
|
||||
<strong>Телефон:</strong> {{ customer.phone|default:"Не указан" }}<br>
|
||||
<strong>Уровень лояльности:</strong> {{ customer.get_loyalty_tier_display }}<br>
|
||||
<strong>VIP:</strong> {% if customer.is_vip %}Да{% else %}Нет{% endif %}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<p class="text-danger"><strong>Внимание:</strong> Это действие нельзя отменить. Все данные клиента будут удалены.</p>
|
||||
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
<div class="d-flex gap-2">
|
||||
<button type="submit" class="btn btn-danger">Да, удалить</button>
|
||||
<a href="{% url 'customers:customer-detail' customer.pk %}" class="btn btn-secondary">Отмена</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
133
myproject/customers/templates/customers/customer_detail.html
Normal file
133
myproject/customers/templates/customers/customer_detail.html
Normal file
@@ -0,0 +1,133 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}{{ customer.full_name }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<h1>Клиент: {{ customer.full_name }}</h1>
|
||||
<div>
|
||||
<a href="{% url 'customers:customer-update' customer.pk %}" class="btn btn-primary">Редактировать</a>
|
||||
<a href="{% url 'customers:customer-delete' customer.pk %}" class="btn btn-danger">Удалить</a>
|
||||
<a href="{% url 'customers:customer-list' %}" class="btn btn-secondary">Назад к списку</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<!-- Customer Info -->
|
||||
<div class="col-md-6">
|
||||
<div class="card mb-4">
|
||||
<div class="card-header">
|
||||
<h5>Информация о клиенте</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<table class="table table-borderless">
|
||||
<tr>
|
||||
<th>Имя:</th>
|
||||
<td>{{ customer.full_name }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Email:</th>
|
||||
<td>{{ customer.email }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Телефон:</th>
|
||||
<td>{{ customer.phone }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Уровень лояльности:</th>
|
||||
<td>
|
||||
<span class="badge
|
||||
{% if customer.loyalty_tier == 'bronze' %}bg-secondary text-dark
|
||||
{% elif customer.loyalty_tier == 'silver' %}bg-light text-dark
|
||||
{% elif customer.loyalty_tier == 'gold' %}bg-warning text-dark
|
||||
{% elif customer.loyalty_tier == 'platinum' %}bg-primary text-white
|
||||
{% endif %}">
|
||||
{{ customer.get_loyalty_tier_display }}
|
||||
</span>
|
||||
<span class="ms-2">({{ customer.get_loyalty_discount }}% скидка)</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Сумма покупок:</th>
|
||||
<td>{{ customer.total_spent|floatformat:2 }} руб.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>VIP:</th>
|
||||
<td>
|
||||
{% if customer.is_vip %}
|
||||
<span class="badge bg-success">Да</span>
|
||||
{% else %}
|
||||
<span class="badge bg-secondary">Нет</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<th>День рождения:</th>
|
||||
<td>{{ customer.birthday|date:"d.m.Y"|default:"Не указан" }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Годовщина:</th>
|
||||
<td>{{ customer.anniversary|date:"d.m.Y"|default:"Не указана" }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Предпочтительные цвета:</th>
|
||||
<td>{{ customer.preferred_colors|default:"Не указаны" }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Заметки:</th>
|
||||
<td>{{ customer.notes|default:"Нет" }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Дата создания:</th>
|
||||
<td>{{ customer.created_at|date:"d.m.Y H:i" }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Дата обновления:</th>
|
||||
<td>{{ customer.updated_at|date:"d.m.Y H:i" }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Addresses -->
|
||||
<div class="col-md-6">
|
||||
<div class="card mb-4">
|
||||
<div class="card-header d-flex justify-content-between align-items-center">
|
||||
<h5>Адреса доставки</h5>
|
||||
<a href="#" class="btn btn-sm btn-outline-primary">Добавить адрес</a>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
{% if addresses %}
|
||||
{% for address in addresses %}
|
||||
<div class="border p-3 mb-3 rounded {% if address.is_default %}border-primary border-2{% endif %}">
|
||||
{% if address.is_default %}
|
||||
<span class="badge bg-primary mb-2">Адрес по умолчанию</span>
|
||||
{% endif %}
|
||||
<h6>{{ address.recipient_name }}</h6>
|
||||
<p class="mb-1">
|
||||
<strong>Адрес:</strong> {{ address.full_address }}, {{ address.district }}
|
||||
</p>
|
||||
{% if address.delivery_instructions %}
|
||||
<p class="mb-1">
|
||||
<strong>Инструкции:</strong> {{ address.delivery_instructions }}
|
||||
</p>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<p>У клиента нет сохраненных адресов доставки.</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
108
myproject/customers/templates/customers/customer_form.html
Normal file
108
myproject/customers/templates/customers/customer_form.html
Normal file
@@ -0,0 +1,108 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}
|
||||
{% if is_creating %}Добавить нового клиента{% else %}Редактировать клиента{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<h1>
|
||||
{% if is_creating %}
|
||||
Добавить нового клиента
|
||||
{% else %}
|
||||
Редактировать клиента
|
||||
{% endif %}
|
||||
</h1>
|
||||
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
|
||||
<div class="row">
|
||||
<!-- Personal Information -->
|
||||
<div class="col-md-6">
|
||||
<div class="card mb-4">
|
||||
<div class="card-header">
|
||||
<h5>Личная информация</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="mb-3">
|
||||
{{ form.name.label_tag }}
|
||||
{{ form.name }}
|
||||
{% if form.name.errors %}
|
||||
<div class="text-danger">{{ form.name.errors }}</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
{{ form.phone.label_tag }}
|
||||
{{ form.phone }}
|
||||
<div class="form-text">Введите телефон в любом формате, например: +375291234567, 80291234567</div>
|
||||
{% if form.phone.errors %}
|
||||
<div class="text-danger">{{ form.phone.errors }}</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
{{ form.email.label_tag }}
|
||||
{{ form.email }}
|
||||
{% if form.email.errors %}
|
||||
<div class="text-danger">{{ form.email.errors }}</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Preferences and Status -->
|
||||
<div class="col-md-6">
|
||||
<div class="card mb-4">
|
||||
<div class="card-header">
|
||||
<h5>Предпочтения и статус</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="mb-3">
|
||||
{{ form.loyalty_tier.label_tag }}
|
||||
{{ form.loyalty_tier }}
|
||||
{% if form.loyalty_tier.errors %}
|
||||
<div class="text-danger">{{ form.loyalty_tier.errors }}</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Additional Information -->
|
||||
<div class="card mb-4">
|
||||
<div class="card-header">
|
||||
<h5>Дополнительная информация</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="mb-3">
|
||||
{{ form.notes.label_tag }}
|
||||
{{ form.notes }}
|
||||
{% if form.notes.errors %}
|
||||
<div class="text-danger">{{ form.notes.errors }}</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Form Actions -->
|
||||
<div class="d-flex gap-2">
|
||||
<button type="submit" class="btn btn-primary">
|
||||
{% if is_creating %}Создать клиента{% else %}Сохранить изменения{% endif %}
|
||||
</button>
|
||||
<a href="{% if form.instance.pk %}{% url 'customers:customer-detail' form.instance.pk %}{% else %}{% url 'customers:customer-list' %}{% endif %}" class="btn btn-secondary">Отмена</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
134
myproject/customers/templates/customers/customer_list.html
Normal file
134
myproject/customers/templates/customers/customer_list.html
Normal file
@@ -0,0 +1,134 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Клиенты{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<h1>Клиенты</h1>
|
||||
<a href="{% url 'customers:customer-create' %}" class="btn btn-primary">Добавить клиента</a>
|
||||
</div>
|
||||
|
||||
<!-- Search Form -->
|
||||
<div class="card mb-4">
|
||||
<div class="card-body">
|
||||
<form method="get" class="row g-3">
|
||||
<div class="col-md-6">
|
||||
<input type="text" class="form-control" name="q"
|
||||
value="{{ query|default:'' }}" placeholder="Поиск по имени, email или телефону...">
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<button type="submit" class="btn btn-outline-primary">Поиск</button>
|
||||
{% if query %}
|
||||
<a href="{% url 'customers:customer-list' %}" class="btn btn-outline-secondary">Очистить</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Customers Table -->
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
|
||||
{% if page_obj %}
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover align-middle">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Имя</th>
|
||||
<th>Email</th>
|
||||
<th>Телефон</th>
|
||||
<th>Уровень лояльности</th>
|
||||
<th>Сумма покупок</th>
|
||||
<th>VIP</th>
|
||||
<th class="text-end">Действия</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for customer in page_obj %}
|
||||
<tr
|
||||
class="{% if customer.is_vip %}table-warning{% endif %}"
|
||||
style="cursor:pointer"
|
||||
onclick="window.location='{% url 'customers:customer-detail' customer.pk %}'"
|
||||
>
|
||||
<td class="fw-semibold">{{ customer.full_name }}</td>
|
||||
<td>{{ customer.email|default:'—' }}</td>
|
||||
<td>{{ customer.phone|default:'—' }}</td>
|
||||
|
||||
<td>
|
||||
<span class="badge
|
||||
{% if customer.loyalty_tier == 'no_discount' %}bg-light text-muted
|
||||
{% elif customer.loyalty_tier == 'bronze' %}bg-secondary text-white
|
||||
{% elif customer.loyalty_tier == 'silver' %}bg-info text-dark
|
||||
{% elif customer.loyalty_tier == 'gold' %}bg-warning text-dark
|
||||
{% elif customer.loyalty_tier == 'platinum' %}bg-primary text-white
|
||||
{% endif %}
|
||||
">
|
||||
{{ customer.get_loyalty_tier_display }}
|
||||
</span>
|
||||
</td>
|
||||
|
||||
<td>{{ customer.total_spent|default:0|floatformat:2 }} ₽</td>
|
||||
|
||||
<td>
|
||||
{% if customer.is_vip %}
|
||||
<span class="badge bg-success">Да</span>
|
||||
{% else %}
|
||||
<span class="badge bg-secondary text-white">Нет</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
|
||||
<td class="text-end" onclick="event.stopPropagation();">
|
||||
<a href="{% url 'customers:customer-detail' customer.pk %}"
|
||||
class="btn btn-sm btn-outline-primary">👁</a>
|
||||
<a href="{% url 'customers:customer-update' customer.pk %}"
|
||||
class="btn btn-sm btn-outline-secondary">✎</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- Pagination -->
|
||||
{% if page_obj.has_other_pages %}
|
||||
<nav aria-label="Page navigation">
|
||||
<ul class="pagination justify-content-center">
|
||||
{% if page_obj.has_previous %}
|
||||
<li class="page-item">
|
||||
<a class="page-link" href="?page={{ page_obj.previous_page_number }}{% if query %}&q={{ query }}{% endif %}">Предыдущая</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
{% for num in page_obj.paginator.page_range %}
|
||||
{% if page_obj.number == num %}
|
||||
<li class="page-item active"><span class="page-link">{{ num }}</span></li>
|
||||
{% elif num > page_obj.number|add:'-3' and num < page_obj.number|add:'3' %}
|
||||
<li class="page-item"><a class="page-link" href="?page={{ num }}{% if query %}&q={{ query }}{% endif %}">{{ num }}</a></li>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
{% if page_obj.has_next %}
|
||||
<li class="page-item">
|
||||
<a class="page-link" href="?page={{ page_obj.next_page_number }}{% if query %}&q={{ query }}{% endif %}">Следующая</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</nav>
|
||||
{% endif %}
|
||||
|
||||
{% else %}
|
||||
<p>Клиенты не найдены.</p>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user