Businessman uchun statistikalar qo'shildi!

This commit is contained in:
Abdulaziz Axmadaliyev
2026-02-19 12:24:00 +05:00
parent 243d879243
commit 241d3c1f20
5 changed files with 339 additions and 168 deletions

View File

@@ -1,164 +1,237 @@
{% extends "base.html" %}
{% block title %}Hisobotlar{% endblock %}
{% block title %}Qurilma Statistikasi{% endblock %}
{% block content %}
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px;">
<h2 style="margin: 0;">{{ title|default:"Hisobotlar" }}</h2>
</div>
<div class="cards-container">
{% if reports %}
{% for report in reports %}
<div class="card">
<div class="card-header">
<div class="card-title">
{{ report.device.address }}
</div>
<div class="card-number">#{{ forloop.counter }}</div>
</div>
<div class="page-card">
<div class="card-content">
<div class="card-row">
<span class="label">Miqdor:</span>
<span class="quantity">{{ report.quantity }} dona</span>
</div>
<div class="card-row">
<span class="label">Sana:</span>
<span class="value">{{ report.created_at|date:"d.m.Y H:i" }}</span>
</div>
<div class="card-row">
<span class="label">Yaratgan:</span>
<span class="value">{{ report.created_by.get_full_name }}</span>
</div>
</div>
</div>
{% endfor %}
{% else %}
<div style="grid-column: 1 / -1; text-align: center; padding: 60px 20px; color: #6b7280;">
<p style="font-style: italic; margin: 0;">Hech qanday hisobot topilmadi</p>
<!-- HEADER -->
<div class="page-header">
<h2 class="page-title">Qurilma Statistikasi</h2>
<p class="page-sub">Qurilmalar bo'yicha kirim, xarajat va foyda hisoboti</p>
</div>
<!-- FILTER -->
<form method="get" class="filter-bar">
<div class="filter-group">
<label class="filter-label">Boshlanish sanasi</label>
<input type="date" name="start_date" value="{{ request.GET.start_date }}" class="filter-input">
</div>
{% endif %}
<div class="filter-group">
<label class="filter-label">Tugash sanasi</label>
<input type="date" name="end_date" value="{{ request.GET.end_date }}" class="filter-input">
</div>
<div class="filter-group">
<label class="filter-label">Qurilma</label>
<select name="device" class="filter-input">
<option value="">— Barchasi —</option>
{% for device in devices %}
<option value="{{ device.id }}"
{% if request.GET.device == device.id|stringformat:"s" %}selected{% endif %}>
{{ device.address }}
</option>
{% endfor %}
</select>
</div>
<div class="filter-actions">
<button type="submit" class="btn-filter">Filtrlash</button>
<a href="?" class="btn-clear">Tozalash</a>
</div>
</form>
<!-- SUMMARY CARDS -->
<div class="summary-row">
<div class="summary-card card-income">
<span class="card-icon">💰</span>
<div>
<div class="card-label">Jami Kirim</div>
<div class="card-value">{{ total_kirim|floatformat:0 }} so'm</div>
</div>
</div>
<div class="summary-card card-expense">
<span class="card-icon">📉</span>
<div>
<div class="card-label">Jami Xarajat</div>
<div class="card-value">{{ total_xarajat|floatformat:0 }} so'm</div>
</div>
</div>
<div class="summary-card {% if total_foyda >= 0 %}card-profit-pos{% else %}card-profit-neg{% endif %}">
<span class="card-icon">{% if total_foyda >= 0 %}📈{% else %}📉{% endif %}</span>
<div>
<div class="card-label">Jami Foyda</div>
<div class="card-value">{{ total_foyda|floatformat:0 }} so'm</div>
</div>
</div>
</div>
<!-- TABLE -->
<div class="table-wrap">
<table>
<thead>
<tr>
<th>#</th>
<th>Qurilma</th>
<th>Miqdor</th>
<th>Kirim</th>
<th>Xarajat</th>
<th>Foyda</th>
<th>Sana</th>
</tr>
</thead>
<tbody>
{% if rows %}
{% for row in rows %}
<tr>
<td class="col-num">{{ forloop.counter }}</td>
<td class="col-device">{{ row.device_name }}</td>
<td><span class="qty-badge">{{ row.quantity }}</span></td>
<td class="col-income">{{ row.kirim|floatformat:0 }} so'm</td>
<td class="col-expense">{{ row.xarajat|floatformat:0 }} so'm</td>
<td>
<span class="foyda-pill {% if row.foyda >= 0 %}foyda-pos{% else %}foyda-neg{% endif %}">
{% if row.foyda >= 0 %}+{% endif %}{{ row.foyda|floatformat:0 }}
</span>
</td>
<td class="col-date">{{ row.date }}</td>
</tr>
{% endfor %}
{% else %}
<tr>
<td colspan="7" class="empty">Hech qanday ma'lumot topilmadi</td>
</tr>
{% endif %}
</tbody>
</table>
</div>
<div class="tbl-footer">
Jami: <strong>{{ rows|length }}</strong> ta yozuv
</div>
<div class="back-link">
<a href="javascript:history.back()">← Orqaga qaytish</a>
</div>
</div>
<style>
.cards-container {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
gap: 16px;
}
.card {
.page-card {
max-width: 1000px;
margin: 32px auto;
background: #fff;
border-radius: 12px;
padding: 16px;
box-shadow: 0 4px 12px rgba(0,0,0,0.05);
transition: all 0.2s ease;
border-left: 4px solid #10b981;
}
border-radius: 16px;
padding: 32px;
box-shadow: 0 4px 24px rgba(0,0,0,0.07);
}
.card:hover {
transform: translateY(-2px);
box-shadow: 0 6px 20px rgba(0,0,0,0.1);
}
.page-header { margin-bottom: 24px; }
.page-title { font-size: 20px; font-weight: 700; color: #111827; margin: 0 0 4px; }
.page-sub { font-size: 13px; color: #6b7280; margin: 0; }
.card-header {
display: flex;
justify-content: space-between;
align-items: start;
margin-bottom: 12px;
padding-bottom: 12px;
border-bottom: 1px solid #e5e7eb;
}
/* FILTER */
.filter-bar {
display: flex; align-items: flex-end; flex-wrap: wrap; gap: 12px;
background: #f9fafb; border: 1px solid #e5e7eb;
border-radius: 10px; padding: 16px 18px; margin-bottom: 24px;
}
.filter-group { display: flex; flex-direction: column; gap: 4px; }
.filter-label {
font-size: 11px; font-weight: 600; color: #6b7280;
text-transform: uppercase; letter-spacing: 0.05em;
}
.filter-input {
padding: 8px 10px; border-radius: 7px;
border: 1.5px solid #d1d5db; background: #fff;
font-size: 13px; color: #111827; outline: none;
min-width: 160px; transition: border-color 0.2s;
}
.filter-input:focus { border-color: #4f46e5; box-shadow: 0 0 0 3px rgba(79,70,229,0.08); }
.filter-actions { display: flex; gap: 8px; align-items: flex-end; }
.btn-filter {
padding: 9px 22px; background: #4f46e5; color: #fff;
border: none; border-radius: 7px; font-size: 13px; font-weight: 600;
cursor: pointer; transition: background 0.2s;
}
.btn-filter:hover { background: #4338ca; }
.btn-clear {
padding: 9px 14px; background: #fff; color: #6b7280;
border: 1.5px solid #d1d5db; border-radius: 7px;
font-size: 13px; font-weight: 600; text-decoration: none;
transition: all 0.2s;
}
.btn-clear:hover { border-color: #9ca3af; color: #374151; }
.card-title {
font-weight: 700;
color: #1f2937;
font-size: 15px;
flex: 1;
}
/* SUMMARY */
.summary-row {
display: grid; grid-template-columns: repeat(3,1fr);
gap: 14px; margin-bottom: 24px;
}
.summary-card {
display: flex; align-items: center; gap: 14px;
border-radius: 10px; padding: 16px 18px;
border: 1.5px solid transparent;
}
.card-income { background: #ecfdf5; border-color: #a7f3d0; }
.card-expense { background: #fef2f2; border-color: #fecaca; }
.card-profit-pos{ background: #eff6ff; border-color: #bfdbfe; }
.card-profit-neg{ background: #fef2f2; border-color: #fecaca; }
.card-icon { font-size: 1.5rem; }
.card-label { font-size: 11px; font-weight: 600; color: #6b7280; text-transform: uppercase; letter-spacing: 0.06em; margin-bottom: 3px; }
.card-value { font-size: 1.05rem; font-weight: 800; color: #111827; }
.card-number {
font-size: 12px;
color: #9ca3af;
font-weight: 600;
}
/* TABLE */
.table-wrap {
border: 1px solid #e5e7eb; border-radius: 10px;
overflow: hidden; overflow-x: auto;
}
table { width: 100%; border-collapse: collapse; font-size: 13px; }
thead tr { background: #f3f4f6; border-bottom: 1.5px solid #e5e7eb; }
th {
padding: 11px 14px; text-align: left;
font-size: 11px; font-weight: 700; color: #6b7280;
text-transform: uppercase; letter-spacing: 0.06em; white-space: nowrap;
}
tbody tr { border-bottom: 1px solid #f3f4f6; transition: background 0.15s; }
tbody tr:last-child { border-bottom: none; }
tbody tr:hover { background: #fafafa; }
td { padding: 12px 14px; vertical-align: middle; color: #374151; }
.card-content {
display: flex;
flex-direction: column;
gap: 8px;
}
.col-num { color: #9ca3af; font-weight: 600; width: 40px; }
.col-device { font-weight: 600; color: #111827; }
.col-income { color: #059669; font-weight: 600; white-space: nowrap; }
.col-expense { color: #dc2626; font-weight: 600; white-space: nowrap; }
.col-date { color: #6b7280; white-space: nowrap; }
.card-row {
display: flex;
justify-content: space-between;
font-size: 13px;
}
.qty-badge {
display: inline-flex; align-items: center; justify-content: center;
width: 30px; height: 30px; border-radius: 50%;
background: #d1fae5; color: #065f46;
font-weight: 700; font-size: 12px;
}
.card-row .label {
color: #6b7280;
font-weight: 500;
}
.foyda-pill {
display: inline-block; padding: 3px 10px; border-radius: 50px;
font-size: 12px; font-weight: 700; white-space: nowrap;
}
.foyda-pos { background: #ecfdf5; color: #059669; }
.foyda-neg { background: #fef2f2; color: #dc2626; }
.card-row .value {
color: #374151;
font-weight: 500;
}
.empty { text-align: center; padding: 48px 20px; color: #9ca3af; font-style: italic; }
.card-row .quantity {
color: #10b981;
font-weight: 700;
}
.tbl-footer { text-align: right; padding: 12px 2px 0; font-size: 13px; color: #6b7280; }
.tbl-footer strong { color: #111827; }
.btn {
display: inline-block;
padding: 8px 14px;
border-radius: 6px;
text-decoration: none;
color: #fff;
font-weight: 600;
font-size: 14px;
transition: all 0.2s ease;
border: none;
cursor: pointer;
}
.back-link { margin-top: 20px; }
.back-link a { color: #4f46e5; font-size: 13px; font-weight: 600; text-decoration: none; }
.back-link a:hover { text-decoration: underline; }
.btn.edit {
background: #4f46e5;
}
.btn.edit:hover {
background: #4338ca;
box-shadow: 0 2px 8px rgba(79,70,229,0.3);
transform: translateY(-1px);
}
@media (max-width: 768px) {
.cards-container {
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
}
.card {
padding: 14px;
}
}
@media (max-width: 480px) {
.cards-container {
grid-template-columns: 1fr;
}
div[style*="display: flex"] {
flex-direction: column;
gap: 10px;
}
.btn {
width: 100%;
text-align: center;
}
}
@media (max-width: 768px) {
.page-card { margin: 12px; padding: 18px; }
.summary-row { grid-template-columns: 1fr; }
.filter-bar { flex-direction: column; }
.filter-input{ min-width: 100%; }
}
</style>
{% endblock %}