Добавлена frontend валидация поиска на странице списка клиентов
Реализовано: - Frontend валидация: минимум 3 символа для запуска поиска - Динамическое отображение подсказки при попытке отправить поиск < 3 символов - Визуальное выделение ошибки (is-invalid класс для input) - Автоматическое скрытие ошибки при вводе 3+ символов Backend уже использует ту же логику оптимизированного поиска: - Те же стратегии поиска (name_only, universal, email и т.д.) - Тот же SQL LIKE запрос для поиска по цифрам телефона - Тот же API эндпоинт api_search_customers() Теперь обе страницы (создание заказа и список клиентов) используют единую оптимизированную логику поиска и требуют минимум 3 символа. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -15,18 +15,57 @@
|
|||||||
<!-- Search Form -->
|
<!-- Search Form -->
|
||||||
<div class="card mb-4">
|
<div class="card mb-4">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<form method="get" class="row g-3">
|
<form method="get" class="row g-3" id="search-form">
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<input type="text" class="form-control" name="q"
|
<input type="text" class="form-control" name="q"
|
||||||
value="{{ query|default:'' }}" placeholder="Поиск по имени, email или телефону (минимум 3 символа)...">
|
value="{{ query|default:'' }}" placeholder="Поиск по имени, email или телефону (минимум 3 символа)..." id="search-input">
|
||||||
|
<small class="form-text text-muted" id="search-hint" style="display: none; color: #dc3545 !important;">
|
||||||
|
Введите минимум 3 символа для поиска
|
||||||
|
</small>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-3">
|
<div class="col-md-3">
|
||||||
<button type="submit" class="btn btn-outline-primary">Поиск</button>
|
<button type="submit" class="btn btn-outline-primary" id="search-btn">Поиск</button>
|
||||||
{% if query %}
|
{% if query %}
|
||||||
<a href="{% url 'customers:customer-list' %}" class="btn btn-outline-secondary">Очистить</a>
|
<a href="{% url 'customers:customer-list' %}" class="btn btn-outline-secondary">Очистить</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
<script>
|
||||||
|
document.getElementById('search-form').addEventListener('submit', function(e) {
|
||||||
|
const searchInput = document.getElementById('search-input');
|
||||||
|
const searchValue = searchInput.value.trim();
|
||||||
|
const searchHint = document.getElementById('search-hint');
|
||||||
|
|
||||||
|
// Если поле пусто или содержит менее 3 символов, не отправляем форму
|
||||||
|
if (searchValue && searchValue.length < 3) {
|
||||||
|
e.preventDefault();
|
||||||
|
searchHint.style.display = 'block';
|
||||||
|
searchInput.classList.add('is-invalid');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Если поле пусто, тоже не отправляем (это будет просто пусто)
|
||||||
|
if (!searchValue) {
|
||||||
|
e.preventDefault();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Все хорошо, отправляем
|
||||||
|
searchHint.style.display = 'none';
|
||||||
|
searchInput.classList.remove('is-invalid');
|
||||||
|
});
|
||||||
|
|
||||||
|
// Убираем ошибку при вводе
|
||||||
|
document.getElementById('search-input').addEventListener('input', function() {
|
||||||
|
const searchValue = this.value.trim();
|
||||||
|
const searchHint = document.getElementById('search-hint');
|
||||||
|
|
||||||
|
if (searchValue.length >= 3) {
|
||||||
|
searchHint.style.display = 'none';
|
||||||
|
this.classList.remove('is-invalid');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user