feat(requests): добавлены фильтры по сотруднику и периоду дат

This commit is contained in:
Игорь Надеин 2025-12-29 15:32:27 +03:00
parent 9772d38a53
commit a7d46c04f5
3 changed files with 75 additions and 5 deletions

View File

@ -239,10 +239,20 @@ class RequestsView(LoginRequiredMixin, TemplateView):
type_ = (request.GET.get("type") or "").strip()
status_ = (request.GET.get("status") or "").strip()
employee_id = (request.GET.get("employee_id") or "").strip()
date_from = (request.GET.get("date_from") or "").strip()
date_to = (request.GET.get("date_to") or "").strip()
if type_:
params["type"] = type_
if status_:
params["status"] = status_
if employee_id:
params["employee_id"] = employee_id
if date_from:
params["date_from"] = date_from
if date_to:
params["date_to"] = date_to
# NB: в API сортировки нет — параметр `ordering` не прокидываем.
@ -254,6 +264,14 @@ class RequestsView(LoginRequiredMixin, TemplateView):
data.get("detail")
or f"Не удалось загрузить список заявлений (HTTP {status}).",
)
# Загружаем список сотрудников для фильтра
employees = []
ok_emp, data_emp, _ = _api_unpack(api.get("v1/employees/", params={"page_size": 1000}))
if ok_emp:
employees_results, _, _, _ = _parse_page_payload(data_emp)
employees = employees_results
ctx.update(
{
"requests": [],
@ -262,10 +280,14 @@ class RequestsView(LoginRequiredMixin, TemplateView):
"count": None,
"scope": scope,
"can_process": _user_can_process_requests(request.user),
"employees": employees,
"filters": {
"type": type_,
"status": status_,
"view": scope,
"employee_id": employee_id,
"date_from": date_from,
"date_to": date_to,
},
}
)
@ -273,6 +295,13 @@ class RequestsView(LoginRequiredMixin, TemplateView):
results, next_url, prev_url, count = _parse_page_payload(data)
# Загружаем список сотрудников для фильтра
employees = []
ok_emp, data_emp, _ = _api_unpack(api.get("v1/employees/", params={"page_size": 1000}))
if ok_emp:
employees_results, _, _, _ = _parse_page_payload(data_emp)
employees = employees_results
ctx.update(
{
"requests": results,
@ -281,10 +310,14 @@ class RequestsView(LoginRequiredMixin, TemplateView):
"count": count,
"scope": scope,
"can_process": _user_can_process_requests(request.user),
"employees": employees,
"filters": {
"type": type_,
"status": status_,
"view": scope,
"employee_id": employee_id,
"date_from": date_from,
"date_to": date_to,
},
}
)

View File

@ -35,6 +35,9 @@ export function initRequestListHandler(options) {
let currentView = urlParams.get("view") || ""; // 'mine' | 'addressed' | ''
let currentType = urlParams.get("type") || "";
let currentStatus = urlParams.get("status") || "";
let currentEmployeeId = urlParams.get("employee_id") || "";
let currentDateFrom = urlParams.get("date_from") || "";
let currentDateTo = urlParams.get("date_to") || "";
let searchQuery = ""; // Поисковый запрос
let allRequests = []; // Все загруженные заявления
let loading = false;
@ -48,7 +51,13 @@ export function initRequestListHandler(options) {
"type =",
currentType,
"status =",
currentStatus
currentStatus,
"employee_id =",
currentEmployeeId,
"date_from =",
currentDateFrom,
"date_to =",
currentDateTo
);
// Intersection Observer для бесконечной прокрутки
@ -114,6 +123,15 @@ export function initRequestListHandler(options) {
if (currentStatus) {
params.append("status", currentStatus);
}
if (currentEmployeeId) {
params.append("employee_id", currentEmployeeId);
}
if (currentDateFrom) {
params.append("date_from", currentDateFrom);
}
if (currentDateTo) {
params.append("date_to", currentDateTo);
}
url = `${apiListUrl}?${params}`;
console.log("loadRequests: initial load", url);

View File

@ -5,7 +5,7 @@
<input type="hidden" name="view" value="{{ filters.view }}">
{% endif %}
<div class="col-12 col-sm-4">
<div class="col-12 col-sm-6 col-md-3">
<label class="form-label mb-1">Тип</label>
<select name="type" class="form-select">
<option value="">— Любой —</option>
@ -17,7 +17,7 @@
<option value="other" {% if filters.type == 'other' %}selected{% endif %}>Другое</option>
</select>
</div>
<div class="col-12 col-sm-4">
<div class="col-12 col-sm-6 col-md-3">
<label class="form-label mb-1">Статус</label>
<select name="status" class="form-select">
<option value="">— Любой —</option>
@ -28,8 +28,27 @@
<option value="cancelled" {% if filters.status == 'cancelled' %}selected{% endif %}>Отменено</option>
</select>
</div>
<div class="col-12 d-flex justify-content-end gap-2 mt-2">
<button class="btn btn-outline-primary d-flex align-items-center justify-content-center gap-1" type="submit">
<div class="col-12 col-sm-6 col-md-3">
<label class="form-label mb-1">Сотрудник</label>
<select name="employee_id" class="form-select">
<option value="">— Любой —</option>
{% for emp in employees %}
<option value="{{ emp.id }}" {% if filters.employee_id|stringformat:"s" == emp.id|stringformat:"s" %}selected{% endif %}>
{{ emp.full_name|default:emp.display_name }}
</option>
{% endfor %}
</select>
</div>
<div class="col-12 col-sm-6 col-md-3">
<label class="form-label mb-1">Период с</label>
<input type="date" name="date_from" class="form-control" value="{{ filters.date_from|default:'' }}">
</div>
<div class="col-12 col-sm-6 col-md-3">
<label class="form-label mb-1">Период по</label>
<input type="date" name="date_to" class="form-control" value="{{ filters.date_to|default:'' }}">
</div>
<div class="col-12 col-sm-6 col-md-3 d-flex align-items-end gap-2">
<button class="btn btn-outline-primary d-flex align-items-center justify-content-center gap-1 flex-fill" type="submit">
<i class="bi-funnel"></i><span>Применить</span>
</button>
<a class="btn btn-outline-secondary d-flex align-items-center justify-content-center" href="?" title="Сбросить фильтры">