Businessman uchun statistikalar qo'shildi!
This commit is contained in:
@@ -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 %}
|
||||
Reference in New Issue
Block a user