All checks were successful
Deploy MES Core / deploy (push) Successful in 13s
288 lines
13 KiB
HTML
288 lines
13 KiB
HTML
{% extends 'base.html' %}
|
||
|
||
{% block content %}
|
||
<div class="card border-secondary mb-3 shadow-sm">
|
||
<div class="card-body py-2">
|
||
<form method="get" class="row g-2 align-items-center">
|
||
<div class="col-md-4">
|
||
<label class="small text-muted mb-1 fw-bold">Станок:</label>
|
||
<select class="form-select form-select-sm bg-body text-body border-secondary" name="machine_id" onchange="this.form.submit()">
|
||
<option value="">— выбрать —</option>
|
||
{% for m in machines %}
|
||
<option value="{{ m.id }}" {% if selected_machine_id == m.id|stringformat:"s" %}selected{% endif %}>{{ m.name }}</option>
|
||
{% endfor %}
|
||
</select>
|
||
</div>
|
||
|
||
<div class="col-md-6">
|
||
<label class="small text-muted mb-1 fw-bold">Материал:</label>
|
||
<select class="form-select form-select-sm bg-body text-body border-secondary" name="material_id" onchange="this.form.submit()">
|
||
<option value="">— выбрать —</option>
|
||
{% for mat in materials %}
|
||
<option value="{{ mat.id }}" {% if selected_material_id == mat.id|stringformat:"s" %}selected{% endif %}>{{ mat.full_name|default:mat.name }}</option>
|
||
{% endfor %}
|
||
</select>
|
||
</div>
|
||
|
||
<div class="col-md-2 text-end mt-auto">
|
||
<a class="btn btn-outline-secondary btn-sm w-100" href="{% url 'closing' %}">Сброс</a>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
|
||
<form method="post">
|
||
{% csrf_token %}
|
||
<input type="hidden" name="machine_id" value="{{ selected_machine_id }}">
|
||
<input type="hidden" name="material_id" value="{{ selected_material_id }}">
|
||
|
||
<div class="card shadow border-secondary mb-3">
|
||
<div class="card-header border-secondary py-3 d-flex justify-content-between align-items-center">
|
||
<h3 class="text-accent mb-0"><i class="bi bi-check2-square me-2"></i>Закрытие</h3>
|
||
</div>
|
||
|
||
<div class="table-responsive">
|
||
<table class="table table-hover mb-0 align-middle">
|
||
<thead>
|
||
<tr class="table-custom-header">
|
||
<th>Дата</th>
|
||
<th>Сделка</th>
|
||
<th>Деталь</th>
|
||
<th>К закрытию</th>
|
||
<th data-sort="false">Факт</th>
|
||
<th data-sort="false">Режим</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
{% for wi in workitems %}
|
||
<tr>
|
||
<td class="small">{{ wi.date|date:"d.m.Y" }}</td>
|
||
<td><span class="text-accent fw-bold">{{ wi.deal.number }}</span></td>
|
||
<td class="fw-bold">{{ wi.entity.drawing_number|default:"—" }} {{ wi.entity.name }}</td>
|
||
<td>{{ wi.remaining }}</td>
|
||
<td style="max-width:140px;">
|
||
<input class="form-control form-control-sm border-secondary" type="number" min="0" max="{{ wi.remaining }}" name="fact_{{ wi.id }}" id="fact_{{ wi.id }}" value="0" {% if not can_edit %}disabled{% endif %}>
|
||
</td>
|
||
<td style="min-width:260px;">
|
||
<div class="d-flex gap-2 align-items-center flex-wrap">
|
||
<button type="button" class="btn btn-sm btn-outline-success closing-set-action" data-item-id="{{ wi.id }}" data-action="done" data-plan="{{ wi.remaining }}" {% if not can_edit %}disabled{% endif %}>Полностью</button>
|
||
<button type="button" class="btn btn-sm btn-outline-warning closing-set-action" data-item-id="{{ wi.id }}" data-action="partial" data-plan="{{ wi.remaining }}" {% if not can_edit %}disabled{% endif %}>Частично</button>
|
||
<input type="hidden" id="ca_{{ wi.id }}" name="close_action_{{ wi.id }}" value="">
|
||
<span class="small text-muted" id="modeLabel_{{ wi.id }}"></span>
|
||
</div>
|
||
</td>
|
||
</tr>
|
||
{% empty %}
|
||
<tr><td colspan="6" class="text-center text-muted py-4">Выбери станок и материал</td></tr>
|
||
{% endfor %}
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="card shadow border-secondary mb-3">
|
||
<div class="card-header border-secondary py-3">
|
||
<h5 class="mb-0">Списание со склада цеха (единицы)</h5>
|
||
</div>
|
||
<div class="table-responsive">
|
||
<table class="table table-hover mb-0 align-middle">
|
||
<thead>
|
||
<tr class="table-custom-header">
|
||
<th>Поступление</th>
|
||
<th>Сделка</th>
|
||
<th>Единица</th>
|
||
<th>Размеры</th>
|
||
<th>Доступно</th>
|
||
<th data-sort="false">Использовано</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
{% for s in stock_items %}
|
||
<tr>
|
||
<td class="small">{% if s.created_at %}{{ s.created_at|date:"d.m.Y H:i" }}{% endif %}</td>
|
||
<td>
|
||
{% if s.deal_id %}
|
||
<span class="text-accent fw-bold">{{ s.deal.number }}</span>
|
||
{% else %}
|
||
—
|
||
{% endif %}
|
||
</td>
|
||
<td>{{ s }}</td>
|
||
<td>
|
||
{% if s.current_length and s.current_width %}
|
||
{{ s.current_length|floatformat:"-g" }} × {{ s.current_width|floatformat:"-g" }} мм
|
||
{% elif s.current_length %}
|
||
{{ s.current_length|floatformat:"-g" }} мм
|
||
{% else %}
|
||
—
|
||
{% endif %}
|
||
</td>
|
||
<td>{{ s.quantity }}</td>
|
||
<td style="max-width:140px;">
|
||
<input class="form-control form-control-sm border-secondary" name="consume_{{ s.id }}" placeholder="0" {% if not can_edit %}disabled{% endif %}>
|
||
</td>
|
||
</tr>
|
||
{% empty %}
|
||
<tr><td colspan="5" class="text-center text-muted py-4">Нет единиц на складе для выбранного материала</td></tr>
|
||
{% endfor %}
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="card shadow border-secondary">
|
||
<div class="card-header border-secondary py-3 d-flex justify-content-between align-items-center">
|
||
<h5 class="mb-0">Остаток ДО</h5>
|
||
<button type="button" class="btn btn-outline-accent btn-sm" id="addRemnantBtn" {% if not can_edit %}disabled{% endif %}>Добавить ДО</button>
|
||
</div>
|
||
<div class="table-responsive">
|
||
<table class="table table-hover mb-0 align-middle">
|
||
<thead>
|
||
<tr class="table-custom-header">
|
||
<th>Кол-во</th>
|
||
<th>Длина (мм)</th>
|
||
<th>Ширина (мм)</th>
|
||
<th data-sort="false"></th>
|
||
</tr>
|
||
</thead>
|
||
<tbody id="remnantBody">
|
||
<tr id="remnantEmptyRow">
|
||
<td colspan="4" class="text-center text-muted py-4">ДО не добавлены</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="d-flex justify-content-end mt-3">
|
||
<button type="submit" class="btn btn-outline-accent" {% if not can_edit %}disabled{% endif %}>Сохранить</button>
|
||
</div>
|
||
</form>
|
||
|
||
<script>
|
||
document.addEventListener('DOMContentLoaded', () => {
|
||
const canEdit = {% if can_edit %}true{% else %}false{% endif %};
|
||
|
||
document.querySelectorAll('.closing-set-action').forEach(btn => {
|
||
btn.addEventListener('click', () => {
|
||
if (!canEdit) return;
|
||
|
||
const itemId = btn.getAttribute('data-item-id');
|
||
const action = btn.getAttribute('data-action');
|
||
const plan = parseInt(btn.getAttribute('data-plan') || '0', 10) || 0;
|
||
|
||
const hidden = document.getElementById('ca_' + itemId);
|
||
const fact = document.getElementById('fact_' + itemId);
|
||
const label = document.getElementById('modeLabel_' + itemId);
|
||
|
||
if (hidden) hidden.value = action;
|
||
|
||
const cell = btn.closest('td');
|
||
if (cell) {
|
||
cell.querySelectorAll('.closing-set-action').forEach(b => {
|
||
const a = b.getAttribute('data-action');
|
||
if (a === 'done') {
|
||
b.classList.remove('btn-success');
|
||
b.classList.add('btn-outline-success');
|
||
}
|
||
if (a === 'partial') {
|
||
b.classList.remove('btn-warning');
|
||
b.classList.add('btn-outline-warning');
|
||
}
|
||
});
|
||
}
|
||
|
||
if (action === 'done') {
|
||
btn.classList.remove('btn-outline-success');
|
||
btn.classList.add('btn-success');
|
||
if (fact) {
|
||
fact.value = String(plan);
|
||
fact.readOnly = true;
|
||
}
|
||
if (label) label.textContent = 'Выбрано: полностью';
|
||
}
|
||
|
||
if (action === 'partial') {
|
||
btn.classList.remove('btn-outline-warning');
|
||
btn.classList.add('btn-warning');
|
||
if (fact) {
|
||
fact.readOnly = false;
|
||
fact.focus();
|
||
fact.select();
|
||
}
|
||
if (label) label.textContent = 'Выбрано: частично';
|
||
}
|
||
});
|
||
});
|
||
|
||
const addBtn = document.getElementById('addRemnantBtn');
|
||
const body = document.getElementById('remnantBody');
|
||
const emptyRow = document.getElementById('remnantEmptyRow');
|
||
|
||
function renumberRemnants() {
|
||
const rows = Array.from(body.querySelectorAll('tr[data-remnant-row="1"]'));
|
||
rows.forEach((tr, idx) => {
|
||
const qty = tr.querySelector('input[data-field="qty"]');
|
||
const len = tr.querySelector('input[data-field="len"]');
|
||
const wid = tr.querySelector('input[data-field="wid"]');
|
||
if (qty) qty.name = 'remnant_qty_' + idx;
|
||
if (len) len.name = 'remnant_len_' + idx;
|
||
if (wid) wid.name = 'remnant_wid_' + idx;
|
||
});
|
||
|
||
if (emptyRow) {
|
||
emptyRow.style.display = rows.length ? 'none' : '';
|
||
}
|
||
}
|
||
|
||
function addRemnantRow() {
|
||
if (!canEdit) return;
|
||
|
||
const rows = Array.from(body.querySelectorAll('tr[data-remnant-row="1"]'));
|
||
if (rows.length >= 50) return;
|
||
|
||
const tr = document.createElement('tr');
|
||
tr.setAttribute('data-remnant-row', '1');
|
||
|
||
tr.innerHTML = `
|
||
<td style="max-width:180px;">
|
||
<input class="form-control form-control-sm border-secondary" data-field="qty" inputmode="decimal" placeholder="Кол-во" required>
|
||
</td>
|
||
<td style="max-width:180px;">
|
||
<input class="form-control form-control-sm border-secondary" data-field="len" inputmode="decimal" placeholder="Длина (мм)">
|
||
</td>
|
||
<td style="max-width:180px;">
|
||
<input class="form-control form-control-sm border-secondary" data-field="wid" inputmode="decimal" placeholder="Ширина (мм)">
|
||
</td>
|
||
<td class="text-end">
|
||
<button type="button" class="btn btn-outline-secondary btn-sm" data-action="remove">Удалить</button>
|
||
</td>
|
||
`;
|
||
|
||
const rm = tr.querySelector('button[data-action="remove"]');
|
||
if (rm) {
|
||
rm.addEventListener('click', () => {
|
||
tr.remove();
|
||
renumberRemnants();
|
||
});
|
||
}
|
||
|
||
body.appendChild(tr);
|
||
renumberRemnants();
|
||
|
||
const first = tr.querySelector('input[data-field="qty"]');
|
||
if (first) {
|
||
first.focus();
|
||
first.select();
|
||
}
|
||
}
|
||
|
||
if (addBtn) {
|
||
addBtn.addEventListener('click', addRemnantRow);
|
||
}
|
||
|
||
renumberRemnants();
|
||
});
|
||
</script>
|
||
|
||
{% endblock %} |