diff --git a/backend/procurement/views_frontend.py b/backend/procurement/views_frontend.py
index 772819ed..7dfa488b 100644
--- a/backend/procurement/views_frontend.py
+++ b/backend/procurement/views_frontend.py
@@ -2,6 +2,7 @@
HTML Views для модуля закупок (Frontend).
"""
+from django.contrib.auth import get_user_model
from django.contrib.auth.decorators import login_required
from django.core.paginator import Paginator
from django.shortcuts import get_object_or_404, render, redirect
@@ -16,6 +17,8 @@ from .models import (
)
from .constants import ProcurementStatus
+User = get_user_model()
+
@login_required
def dashboard(request):
@@ -246,6 +249,9 @@ def equipment_list(request):
'filters': filters,
'categories': EquipmentCategory.objects.all(),
'departments': Department.objects.all(),
+ 'users': User.objects.filter(
+ is_active=True
+ ).order_by('last_name', 'first_name'),
'can_manage': request.user.is_staff,
}
return render(request, 'procurement/equipment_list.html', context)
diff --git a/backend/templates/procurement/equipment_list.html b/backend/templates/procurement/equipment_list.html
index 7679a439..11d9dc24 100644
--- a/backend/templates/procurement/equipment_list.html
+++ b/backend/templates/procurement/equipment_list.html
@@ -11,7 +11,7 @@
{% block content %}
{# ===== ШАПКА СТРАНИЦЫ ===== #}
- {% include "includes/components/page_header.html" with icon="bi-laptop" title="Оборудование" search_id="eqSearch" search_placeholder="Поиск по названию или инв. номеру..." has_filters=True filters_target="eqFilters" filters_template="procurement/_equipment_filters.html" %}
+ {% include "includes/components/page_header.html" with icon="bi-laptop" title="Оборудование" search_id="eqSearch" search_placeholder="Поиск по названию или инв. номеру..." has_filters=True filters_target="eqFilters" filters_template="procurement/_equipment_filters.html" create_as_card=True create_modal="equipmentCreateModal" create_text="Добавить оборудование" %}
{# ===== СЕТКА ОБОРУДОВАНИЯ ===== #}
{% endif %}
+{# ===== МОДАЛКА СОЗДАНИЯ ОБОРУДОВАНИЯ ===== #}
+
+
+{# ===== МОДАЛКА РЕДАКТИРОВАНИЯ ОБОРУДОВАНИЯ ===== #}
+
+
+
+
+
+
{# ===== МОДАЛКА ПЕРЕВОДА ===== #}
@@ -347,5 +567,143 @@
alert('Ошибка сети');
}
});
+
+ // === СОЗДАНИЕ ОБОРУДОВАНИЯ ===
+ document.getElementById('equipmentCreateForm')?.addEventListener('submit', async (e) => {
+ e.preventDefault();
+ const form = e.target;
+ const submitBtn = form.querySelector('[type="submit"]');
+ const formData = new FormData(form);
+ const data = Object.fromEntries(formData.entries());
+
+ // Убираем пустые значения
+ Object.keys(data).forEach(key => {
+ if (data[key] === '') delete data[key];
+ });
+
+ submitBtn.disabled = true;
+ submitBtn.innerHTML = 'Создание...';
+
+ try {
+ const resp = await fetch('/api/procurement/equipment/', {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ 'X-CSRFToken': formData.get('csrfmiddlewaretoken')
+ },
+ body: JSON.stringify(data)
+ });
+
+ if (resp.ok) {
+ const result = await resp.json();
+ bootstrap.Modal.getInstance(document.getElementById('equipmentCreateModal')).hide();
+ form.reset();
+ // Перезагрузить страницу или добавить в список
+ window.location.href = `/procurement/equipment/${result.id}/`;
+ } else {
+ const err = await resp.json();
+ let errorMsg = 'Ошибка создания';
+ if (err.inventory_number) {
+ errorMsg = 'Инвентарный номер уже существует';
+ } else if (err.detail) {
+ errorMsg = err.detail;
+ }
+ alert(errorMsg);
+ }
+ } catch (e) {
+ console.error(e);
+ alert('Ошибка сети');
+ } finally {
+ submitBtn.disabled = false;
+ submitBtn.innerHTML = 'Добавить';
+ }
+ });
+
+ // === РЕДАКТИРОВАНИЕ ОБОРУДОВАНИЯ ===
+ // Загрузка данных при открытии модала
+ document.getElementById('equipmentEditModal')?.addEventListener('show.bs.modal', async (e) => {
+ const button = e.relatedTarget;
+ const equipmentId = button.getAttribute('data-id');
+
+ if (!equipmentId) return;
+
+ document.getElementById('editEquipmentId').value = equipmentId;
+
+ try {
+ const resp = await fetch(`/api/procurement/equipment/${equipmentId}/`);
+ if (resp.ok) {
+ const eq = await resp.json();
+
+ document.getElementById('editName').value = eq.name || '';
+ document.getElementById('editInventoryNumber').value = eq.inventory_number || '';
+ document.getElementById('editSerialNumber').value = eq.serial_number || '';
+ document.getElementById('editCategory').value = eq.category || '';
+ document.getElementById('editStatus').value = eq.status || 'available';
+ document.getElementById('editDepartment').value = eq.department || '';
+ document.getElementById('editResponsiblePerson').value = eq.responsible_person || '';
+ document.getElementById('editLocation').value = eq.location || '';
+ document.getElementById('editPurchaseDate').value = eq.purchase_date || '';
+ document.getElementById('editWarrantyUntil').value = eq.warranty_until || '';
+ document.getElementById('editPurchaseCost').value = eq.purchase_cost || '';
+ document.getElementById('editNotes').value = eq.notes || '';
+ } else {
+ alert('Ошибка загрузки данных');
+ }
+ } catch (e) {
+ console.error(e);
+ alert('Ошибка сети');
+ }
+ });
+
+ // Сохранение изменений
+ document.getElementById('equipmentEditForm')?.addEventListener('submit', async (e) => {
+ e.preventDefault();
+ const form = e.target;
+ const submitBtn = form.querySelector('[type="submit"]');
+ const equipmentId = form.querySelector('#editEquipmentId').value;
+ const formData = new FormData(form);
+ const data = Object.fromEntries(formData.entries());
+ delete data.equipment_id; // Убираем служебное поле
+
+ // Убираем пустые значения
+ Object.keys(data).forEach(key => {
+ if (data[key] === '') data[key] = null;
+ });
+
+ submitBtn.disabled = true;
+ submitBtn.innerHTML = 'Сохранение...';
+
+ try {
+ const resp = await fetch(`/api/procurement/equipment/${equipmentId}/`, {
+ method: 'PATCH',
+ headers: {
+ 'Content-Type': 'application/json',
+ 'X-CSRFToken': formData.get('csrfmiddlewaretoken')
+ },
+ body: JSON.stringify(data)
+ });
+
+ if (resp.ok) {
+ bootstrap.Modal.getInstance(document.getElementById('equipmentEditModal')).hide();
+ // Перезагрузить страницу
+ window.location.reload();
+ } else {
+ const err = await resp.json();
+ let errorMsg = 'Ошибка сохранения';
+ if (err.inventory_number) {
+ errorMsg = 'Инвентарный номер уже существует';
+ } else if (err.detail) {
+ errorMsg = err.detail;
+ }
+ alert(errorMsg);
+ }
+ } catch (e) {
+ console.error(e);
+ alert('Ошибка сети');
+ } finally {
+ submitBtn.disabled = false;
+ submitBtn.innerHTML = 'Сохранить изменения';
+ }
+ });
{% endblock %}