Конкретно пересмотрел логику работы. Легаси вынесена в архив
All checks were successful
Deploy MES Core / deploy (push) Successful in 13s
All checks were successful
Deploy MES Core / deploy (push) Successful in 13s
This commit is contained in:
218
shiftflow/templates/shiftflow/procurement_dashboard.html
Normal file
218
shiftflow/templates/shiftflow/procurement_dashboard.html
Normal file
@@ -0,0 +1,218 @@
|
||||
{% extends 'base.html' %}
|
||||
|
||||
{% block content %}
|
||||
<div class="card shadow border-secondary">
|
||||
<div class="card-header border-secondary py-3 d-flex justify-content-between align-items-center">
|
||||
<div class="w-100">
|
||||
<div class="d-flex flex-wrap align-items-center gap-3 justify-content-between">
|
||||
<h3 class="text-accent mb-0"><i class="bi bi-truck me-2"></i>Снабжение</h3>
|
||||
|
||||
<form method="get" class="d-flex flex-wrap align-items-center gap-2">
|
||||
<input type="hidden" name="filtered" value="1">
|
||||
|
||||
<div class="d-flex w-100 mb-2 gap-2">
|
||||
<input type="text" class="form-control form-control-sm border-secondary" name="q" placeholder="Сделка / компонент" value="{{ q }}" style="max-width: 300px;">
|
||||
<button type="submit" class="btn btn-outline-accent btn-sm">
|
||||
<i class="bi bi-search me-1"></i>Применить
|
||||
</button>
|
||||
<a class="btn btn-outline-secondary btn-sm" href="{% url 'procurement' %}">Сброс</a>
|
||||
|
||||
<div class="ms-auto">
|
||||
<button type="submit" name="print" value="1" class="btn btn-outline-secondary btn-sm" formtarget="_blank">
|
||||
<i class="bi bi-printer me-1"></i>Печать
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="d-flex align-items-center gap-1">
|
||||
<input type="checkbox" class="btn-check" name="grouped" id="grouped" value="1" {% if grouped %}checked{% endif %} onchange="this.form.submit()">
|
||||
<label class="btn btn-outline-accent btn-sm" for="grouped"><i class="bi bi-layers me-1"></i>Группировать</label>
|
||||
</div>
|
||||
|
||||
<div class="d-flex flex-wrap align-items-center gap-1">
|
||||
<span class="small text-muted me-1">Тип:</span>
|
||||
{% for code, label in type_choices %}
|
||||
<input type="checkbox" class="btn-check" name="types" id="type_{{ code }}" value="{{ code }}" {% if code in selected_types %}checked{% endif %} onchange="this.form.submit()">
|
||||
<label class="btn btn-sm {% if code == 'raw' %}btn-outline-info{% elif code == 'purchased' %}btn-outline-primary{% elif code == 'casting' %}btn-outline-secondary{% elif code == 'outsourced' %}btn-outline-warning{% else %}btn-outline-secondary{% endif %}" for="type_{{ code }}">{{ label }}</label>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<div class="d-flex flex-wrap align-items-center gap-1">
|
||||
<span class="small text-muted me-1">Статус:</span>
|
||||
{% for code, label in status_choices %}
|
||||
<input type="checkbox" class="btn-check" name="statuses" id="st_{{ code }}" value="{{ code }}" {% if code in selected_statuses %}checked{% endif %} onchange="this.form.submit()">
|
||||
<label class="btn btn-sm {% if code == 'to_order' %}btn-outline-danger{% elif code == 'ordered' %}btn-outline-warning{% else %}btn-outline-success{% endif %}" for="st_{{ code }}">{{ label }}</label>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card-body p-0">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover mb-0 align-middle" data-sortable="1">
|
||||
<thead>
|
||||
<tr class="table-custom-header">
|
||||
<th>Компонент</th>
|
||||
<th style="width: 140px;">Тип</th>
|
||||
<th style="width: 140px;">К заказу</th>
|
||||
<th style="width: 220px;">Сделки</th>
|
||||
<th style="width: 140px;">Статус</th>
|
||||
<th style="width: 70px;" data-sort="false"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for r in requirements %}
|
||||
<tr>
|
||||
<td>
|
||||
<div class="fw-semibold">{{ r.component_label }}</div>
|
||||
</td>
|
||||
<td class="small">
|
||||
{% if r.type == 'raw' %}Сырьё{% elif r.type == 'purchased' %}Покупное{% elif r.type == 'casting' %}Литьё{% elif r.type == 'outsourced' %}Аутсорс{% else %}—{% endif %}
|
||||
</td>
|
||||
<td class="fw-semibold">
|
||||
{{ r.required_qty }}{% if r.kind == 'raw' %} {{ r.unit }}{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if r.deals and r.deals|length > 0 %}
|
||||
{% for dn in r.deals|slice:":3" %}
|
||||
<span class="badge bg-secondary">{{ dn }}</span>
|
||||
{% endfor %}
|
||||
{% if r.deals|length > 3 %}
|
||||
<span class="badge bg-secondary" title="{{ r.deals|join:", " }}">…</span>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<span class="text-muted">—</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if r.status == 'to_order' %}
|
||||
<span class="badge bg-danger">К заказу</span>
|
||||
{% elif r.status == 'ordered' %}
|
||||
<span class="badge bg-warning text-dark">Заказано</span>
|
||||
{% else %}
|
||||
<span class="badge bg-success">Закрыто</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="text-end">
|
||||
{% if can_edit and not grouped and r.kind == 'component' %}
|
||||
{% if r.status == 'to_order' %}
|
||||
<form method="post" class="d-inline">
|
||||
{% csrf_token %}
|
||||
<input type="hidden" name="action" value="mark_ordered">
|
||||
<input type="hidden" name="pr_id" value="{{ r.obj_id }}">
|
||||
<input type="hidden" name="next" value="{{ request.get_full_path }}">
|
||||
<button type="submit" class="btn btn-outline-accent btn-sm" title="Отметить как заказано">+</button>
|
||||
</form>
|
||||
{% elif r.status == 'ordered' %}
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-outline-accent btn-sm"
|
||||
title="Оформить приход"
|
||||
data-bs-toggle="modal"
|
||||
data-bs-target="#receiveModal"
|
||||
data-pr-id="{{ r.obj_id }}"
|
||||
data-label="{{ r.component_label }}"
|
||||
data-deal-id="{{ r.deal_id }}"
|
||||
data-deal-number="{{ r.deals.0 }}"
|
||||
data-max="{{ r.required_qty }}"
|
||||
>+</button>
|
||||
{% else %}
|
||||
<span class="text-muted">—</span>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<span class="text-muted">—</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% empty %}
|
||||
<tr><td colspan="6" class="text-center p-5 text-muted">Потребностей не найдено</td></tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal fade" id="receiveModal" tabindex="-1" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<form method="post" class="modal-content border-secondary">
|
||||
{% csrf_token %}
|
||||
<input type="hidden" name="action" value="receive_component">
|
||||
<input type="hidden" name="next" value="{{ request.get_full_path }}">
|
||||
<input type="hidden" name="pr_id" id="receivePrId">
|
||||
|
||||
<div class="modal-header border-secondary">
|
||||
<h5 class="modal-title">Приход компонента</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Закрыть"></button>
|
||||
</div>
|
||||
|
||||
<div class="modal-body">
|
||||
<div class="mb-2 small text-muted" id="receiveLabel"></div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Склад</label>
|
||||
<select class="form-select border-secondary" name="location_id" required>
|
||||
{% for loc in locations %}
|
||||
<option value="{{ loc.id }}">{{ loc.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Сделка (опционально)</label>
|
||||
<select class="form-select border-secondary" name="deal_id" id="receiveDealId">
|
||||
<option value="">Свободно</option>
|
||||
{% for d in deals %}
|
||||
<option value="{{ d.id }}">{{ d.number }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Количество (шт)</label>
|
||||
<input class="form-control border-secondary" name="quantity" id="receiveQty" placeholder="Напр. 100" required>
|
||||
<div class="form-text">Количество уменьшит потребность выбранной строки. При достижении 0 статус станет «Закрыто».</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal-footer border-secondary">
|
||||
<button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">Отмена</button>
|
||||
<button type="submit" class="btn btn-outline-accent">Оформить</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
(function () {
|
||||
const modal = document.getElementById('receiveModal');
|
||||
if (!modal) return;
|
||||
|
||||
const prId = document.getElementById('receivePrId');
|
||||
const label = document.getElementById('receiveLabel');
|
||||
const dealId = document.getElementById('receiveDealId');
|
||||
const qty = document.getElementById('receiveQty');
|
||||
|
||||
modal.addEventListener('show.bs.modal', function (event) {
|
||||
const btn = event.relatedTarget;
|
||||
if (!btn) return;
|
||||
const id = btn.getAttribute('data-pr-id') || '';
|
||||
const text = btn.getAttribute('data-label') || '';
|
||||
const max = btn.getAttribute('data-max') || '';
|
||||
const dId = btn.getAttribute('data-deal-id') || '';
|
||||
const dNum = btn.getAttribute('data-deal-number') || '';
|
||||
|
||||
if (prId) prId.value = id;
|
||||
if (label) label.textContent = (text ? ('Компонент: ' + text) : '') + (dNum ? (' · Сделка: ' + dNum) : '');
|
||||
if (dealId) dealId.value = dId;
|
||||
if (qty) {
|
||||
qty.value = max || '';
|
||||
qty.focus();
|
||||
qty.select();
|
||||
}
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user