Игорь Надеин 53a8f0e6b4 feat: add procurement frontend templates and styles
Stage 6 - Frontend Implementation:
- Add procurement.css with iOS-style components
- Add dashboard, request_list, request_detail, request_form templates
- Add equipment_list, equipment_detail templates
- Add status badges and filters partials
- Add JS handlers for dashboard, requests and equipment
- Add procurement link to sidebar navigation
- Configure separate URL namespaces (procurement for API, procurement_frontend for views)

All 66 tests passing.
2025-12-09 12:03:58 +03:00

239 lines
9.1 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{% extends "base.html" %}
{% load static %}
{% block title %}Закупки{% endblock %}
{% block extra_css %}
<link rel="stylesheet" href="{% static 'css/components/page-header.css' %}">
<link rel="stylesheet" href="{% static 'css/components/procurement.css' %}">
{% endblock %}
{% block content %}
{# ===== ШАПКА СТРАНИЦЫ ===== #}
{% include "includes/components/page_header.html" with icon="bi-cart3" title="Закупки" no_search=True create_url=create_url create_text="Новая заявка" %}
{# ===== СТАТИСТИКА ===== #}
<div class="proc-stats">
<div class="proc-stat-card">
<div class="proc-stat-icon pending">
<i class="bi-hourglass-split"></i>
</div>
<div class="proc-stat-content">
<div class="proc-stat-value" id="statPending">{{ stats.pending|default:0 }}</div>
<div class="proc-stat-label">На согласовании</div>
</div>
</div>
<div class="proc-stat-card">
<div class="proc-stat-icon approved">
<i class="bi-check-circle"></i>
</div>
<div class="proc-stat-content">
<div class="proc-stat-value" id="statApproved">{{ stats.approved|default:0 }}</div>
<div class="proc-stat-label">Одобрено</div>
</div>
</div>
<div class="proc-stat-card">
<div class="proc-stat-icon budget">
<i class="bi-wallet2"></i>
</div>
<div class="proc-stat-content">
<div class="proc-stat-value" id="statBudget">
{% if budget %}
{{ budget.remaining_percent|floatformat:0 }}%
{% else %}
—
{% endif %}
</div>
<div class="proc-stat-label">Бюджет отдела</div>
</div>
</div>
<div class="proc-stat-card">
<div class="proc-stat-icon equipment">
<i class="bi-pc-display"></i>
</div>
<div class="proc-stat-content">
<div class="proc-stat-value" id="statEquipment">{{ stats.equipment|default:0 }}</div>
<div class="proc-stat-label">Оборудование</div>
</div>
</div>
</div>
{# ===== БЫСТРЫЕ ДЕЙСТВИЯ ===== #}
<div class="row g-3 mb-4">
<div class="col-md-6 col-lg-3">
<a href="{% url 'procurement_frontend:request_list' %}" class="card text-decoration-none h-100">
<div class="card-body text-center py-4">
<i class="bi-list-ul text-primary fs-1 mb-2 d-block"></i>
<h6 class="mb-1">Заявки</h6>
<small class="text-muted">Все заявки на закупку</small>
</div>
</a>
</div>
<div class="col-md-6 col-lg-3">
<a href="{% url 'procurement_frontend:my_requests' %}" class="card text-decoration-none h-100">
<div class="card-body text-center py-4">
<i class="bi-person-circle text-info fs-1 mb-2 d-block"></i>
<h6 class="mb-1">Мои заявки</h6>
<small class="text-muted">Созданные мной</small>
</div>
</a>
</div>
<div class="col-md-6 col-lg-3">
<a href="{% url 'procurement_frontend:equipment_list' %}" class="card text-decoration-none h-100">
<div class="card-body text-center py-4">
<i class="bi-laptop text-success fs-1 mb-2 d-block"></i>
<h6 class="mb-1">Оборудование</h6>
<small class="text-muted">Каталог инвентаря</small>
</div>
</a>
</div>
{% if can_approve %}
<div class="col-md-6 col-lg-3">
<a href="{% url 'procurement_frontend:pending_approvals' %}" class="card text-decoration-none h-100">
<div class="card-body text-center py-4">
<i class="bi-clipboard-check text-warning fs-1 mb-2 d-block"></i>
<h6 class="mb-1">Согласование</h6>
<small class="text-muted">Ожидают решения</small>
</div>
</a>
</div>
{% endif %}
</div>
{# ===== МОЙ БЮДЖЕТ (если есть) ===== #}
{% if budget %}
<div class="card mb-4">
<div class="card-header">
<h5 class="mb-0">
<i class="bi-pie-chart me-2"></i>Бюджет отдела на {{ budget.quarter }} кв. {{ budget.year }}
</h5>
</div>
<div class="card-body">
<div class="proc-budget-amounts">
<div class="proc-budget-amount">
<div class="proc-budget-value text-success">{{ budget.allocated_amount|floatformat:0 }} ₽</div>
<div class="proc-budget-label">Выделено</div>
</div>
<div class="proc-budget-amount">
<div class="proc-budget-value text-danger">{{ budget.spent_amount|floatformat:0 }} ₽</div>
<div class="proc-budget-label">Потрачено</div>
</div>
<div class="proc-budget-amount">
<div class="proc-budget-value text-warning">{{ budget.reserved_amount|floatformat:0 }} ₽</div>
<div class="proc-budget-label">Зарезервировано</div>
</div>
<div class="proc-budget-amount">
<div class="proc-budget-value text-primary">{{ budget.available_amount|floatformat:0 }} ₽</div>
<div class="proc-budget-label">Доступно</div>
</div>
</div>
<div class="proc-budget-progress">
{% with percent=budget.spent_percent %}
<div class="proc-budget-bar {% if percent > 80 %}danger{% elif percent > 60 %}warning{% else %}safe{% endif %}"
style="width: {{ percent|floatformat:0 }}%"></div>
{% endwith %}
</div>
<div class="text-end mt-2">
<small class="text-muted">
Использовано {{ budget.spent_percent|floatformat:0 }}% бюджета
</small>
</div>
</div>
</div>
{% endif %}
{# ===== ПОСЛЕДНИЕ ЗАЯВКИ ===== #}
<div class="card mb-4">
<div class="card-header d-flex align-items-center justify-content-between">
<h5 class="mb-0">
<i class="bi-clock-history me-2"></i>Последние заявки
</h5>
<a href="{% url 'procurement_frontend:request_list' %}" class="btn btn-sm btn-outline-primary">
Все заявки <i class="bi-arrow-right"></i>
</a>
</div>
<div class="card-body p-0">
{% if recent_requests %}
<div class="proc-table-header d-none d-lg-block">
<div class="proc-table-row">
<div class="proc-cell"></div>
<div class="proc-cell"><h6 class="mb-0 text-secondary">Заявка</h6></div>
<div class="proc-cell"><h6 class="mb-0 text-secondary">Отдел</h6></div>
<div class="proc-cell"><h6 class="mb-0 text-secondary">Сумма</h6></div>
<div class="proc-cell"><h6 class="mb-0 text-secondary">Статус</h6></div>
<div class="proc-cell"><h6 class="mb-0 text-secondary">Дата</h6></div>
</div>
</div>
{% for request in recent_requests %}
<div class="proc-request-item">
<div class="proc-urgency-icon {{ request.urgency }}">
{% if request.urgency == 'critical' %}
<i class="bi-exclamation-triangle-fill"></i>
{% elif request.urgency == 'high' %}
<i class="bi-arrow-up-circle"></i>
{% elif request.urgency == 'medium' %}
<i class="bi-dash-circle"></i>
{% else %}
<i class="bi-arrow-down-circle"></i>
{% endif %}
</div>
<div class="proc-request-info">
<div class="proc-request-title">
<a href="{% url 'procurement_frontend:request_detail' request.id %}">{{ request.title }}</a>
</div>
<div class="proc-request-desc">{{ request.description|truncatechars:50 }}</div>
</div>
<div class="proc-request-dept">{{ request.department.name }}</div>
<div class="proc-request-amount">{{ request.estimated_cost|floatformat:0 }} ₽</div>
<div class="proc-request-status">
{% include "procurement/_status_badge.html" with status=request.status %}
</div>
<div class="proc-request-date">
{{ request.created_at|date:"d.m.Y" }}
</div>
</div>
{% endfor %}
{% else %}
<div class="text-center py-5 text-muted">
<i class="bi-inbox fs-1 d-block mb-2"></i>
<p class="mb-0">Заявок пока нет</p>
</div>
{% endif %}
</div>
</div>
{% endblock %}
{% block extra_js %}
<script>
// Автообновление статистики каждые 60 секунд
setInterval(async () => {
try {
const resp = await fetch('/api/procurement/stats/overview/');
if (resp.ok) {
const data = await resp.json();
document.getElementById('statPending').textContent = data.pending || 0;
document.getElementById('statApproved').textContent = data.approved || 0;
document.getElementById('statEquipment').textContent = data.equipment || 0;
}
} catch (e) {
console.warn('Stats update failed:', e);
}
}, 60000);
</script>
{% endblock %}