Files
MES_Core/shiftflow/templates/shiftflow/planning_deal.html

212 lines
10 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' %}
{% block content %}
<div class="card shadow border-secondary mb-3">
<div class="card-header border-secondary py-3 d-flex justify-content-between align-items-center">
<div>
<h3 class="text-accent mb-1">
<i class="bi bi-briefcase me-2"></i>Сделка {{ deal.number }}
</h3>
<div class="small text-muted">
{% if deal.company %}{{ deal.company.name }}{% else %}—{% endif %}
{% if deal.description %} · {{ deal.description }}{% endif %}
</div>
</div>
<div class="d-flex gap-2">
<span class="badge {% if deal.status == 'work' %}bg-primary{% elif deal.status == 'done' %}bg-success{% else %}bg-secondary{% endif %} align-self-center">
{{ deal.get_status_display }}
</span>
<a class="btn btn-outline-secondary btn-sm" href="{% url 'planning' %}">
<i class="bi bi-arrow-left me-1"></i>Назад
</a>
{% if user_role in 'admin,technologist' %}
<a class="btn btn-outline-accent btn-sm" href="{% url 'task_add' %}?deal={{ deal.id }}&next={% url 'planning_deal' deal.id %}">
<i class="bi bi-plus-lg me-1"></i>Добавить деталь
</a>
{% endif %}
</div>
</div>
<div class="card-body p-0">
<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 style="width: 160px;">Прогресс</th>
<th class="text-center">Надо / Сделано / В плане</th>
<th class="text-center">Осталось</th>
<th class="text-center">Файлы</th>
<th class="text-end">Действия</th>
</tr>
</thead>
<tbody>
{% for t in tasks %}
<tr class="task-row" style="cursor:pointer" data-href="{% url 'task_items' t.id %}">
<td class="fw-bold">{{ t.drawing_name|default:"Б/ч" }}</td>
<td class="small text-muted">{{ t.material.full_name|default:t.material.name }}</td>
<td class="small">{{ t.size_value }}</td>
<td>
<div class="progress bg-secondary-subtle border border-secondary sf-progress" style="height: 10px;" data-done-width="{{ t.done_width }}" data-plan-width="{{ t.plan_width }}" title="Сделано: {{ t.done_pct }}% · В плане: {{ t.plan_pct }}%">
<div class="progress-bar bg-success sf-progress-done"></div>
<div class="progress-bar bg-warning sf-progress-plan"></div>
</div>
</td>
<td class="text-center">
<span class="text-info fw-bold">{{ t.quantity_ordered }}</span> /
<span class="text-success">{{ t.done_qty }}</span> /
<span class="text-warning">{{ t.planned_qty }}</span>
</td>
<td class="text-center">{{ t.remaining_qty }}</td>
<td class="text-center">
{% if t.drawing_file %}
<a href="{{ t.drawing_file.url }}" target="_blank" class="btn btn-sm btn-outline-info p-1 stop-prop" title="DXF/IGES">
<i class="bi bi-file-earmark-code"></i>
</a>
{% endif %}
{% if t.extra_drawing %}
<a href="{{ t.extra_drawing.url }}" target="_blank" class="btn btn-sm btn-outline-danger p-1 stop-prop" title="Чертеж PDF">
<i class="bi bi-file-pdf"></i>
</a>
{% endif %}
</td>
<td class="text-end">
{% if user_role in 'admin,technologist' %}
<button
type="button"
class="btn btn-outline-accent btn-sm"
data-bs-toggle="modal"
data-bs-target="#addToPlanModal"
data-task-id="{{ t.id }}"
data-task-name="{{ t.drawing_name|default:'Б/ч' }}"
data-task-rem="{{ t.remaining_qty }}"
>
<i class="bi bi-plus-lg me-1"></i>В план
</button>
{% endif %}
</td>
</tr>
{% empty %}
<tr><td colspan="8" class="text-center p-5 text-muted">Деталей не найдено</td></tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
<div class="modal fade" id="addToPlanModal" tabindex="-1" aria-hidden="true">
<div class="modal-dialog">
<form method="post" action="{% url 'planning_add' %}" class="modal-content border-secondary">
{% csrf_token %}
<input type="hidden" name="next" value="{{ request.get_full_path }}">
<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">
<input type="hidden" name="task_id" id="modalTaskId">
<div class="small text-muted mb-2" id="modalTaskTitle"></div>
<div class="mb-3">
<label class="form-label small text-muted d-block">Станок</label>
<div class="d-flex flex-wrap gap-1" id="machineToggleGroup">
{% for m in machines %}
<input type="radio" class="btn-check" name="machine_id" id="m_{{ m.id }}" value="{{ m.id }}" required>
<label class="btn btn-outline-accent btn-sm" for="m_{{ m.id }}">{{ m.name }}</label>
{% endfor %}
</div>
</div>
<div class="mb-2">
<label class="form-label small text-muted">Сколько в план (шт)</label>
<input type="number" min="1" class="form-control border-secondary" name="quantity_plan" id="modalQty" required>
</div>
<div class="small text-muted" id="modalHint"></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>
document.addEventListener('DOMContentLoaded', function () {
document.querySelectorAll('tr.task-row[data-href]').forEach(function (row) {
row.addEventListener('click', function (e) {
if (e.target && (e.target.closest('button') || e.target.closest('.stop-prop'))) return;
const href = row.getAttribute('data-href');
if (href) window.location.href = href;
});
});
document.querySelectorAll('.sf-progress').forEach(function (el) {
const done = parseInt(el.getAttribute('data-done-width') || '0', 10) || 0;
const plan = parseInt(el.getAttribute('data-plan-width') || '0', 10) || 0;
const doneEl = el.querySelector('.sf-progress-done');
const planEl = el.querySelector('.sf-progress-plan');
if (doneEl) doneEl.style.width = `${done}%`;
if (planEl) planEl.style.width = `${plan}%`;
});
const modal = document.getElementById('addToPlanModal');
if (!modal) return;
modal.addEventListener('shown.bs.modal', function (event) {
const btn = event.relatedTarget;
const taskId = btn.getAttribute('data-task-id');
const name = btn.getAttribute('data-task-name');
const rem = btn.getAttribute('data-task-rem');
document.getElementById('modalTaskId').value = taskId;
document.getElementById('modalTaskTitle').textContent = name;
document.getElementById('modalHint').textContent = rem !== null ? `Осталось: ${rem} шт` : '';
const qty = document.getElementById('modalQty');
qty.value = '';
let remInt = null;
if (rem && !isNaN(parseInt(rem, 10))) {
remInt = Math.max(1, parseInt(rem, 10));
qty.max = remInt;
qty.value = String(remInt);
} else {
qty.removeAttribute('max');
}
qty.focus({ preventScroll: true });
qty.select();
qty.onkeydown = function (e) {
if (e.key === 'Enter') {
e.preventDefault();
const form = document.querySelector('#addToPlanModal form');
if (form) form.requestSubmit();
}
};
const radios = Array.from(document.querySelectorAll('input[name="machine_id"]'));
const savedMachine = (() => { try { return localStorage.getItem('planning_machine_id'); } catch (_) { return null; } })();
let selected = null;
if (savedMachine) {
selected = radios.find(r => r.value === savedMachine);
}
if (!selected && radios.length) selected = radios[0];
if (selected) selected.checked = true;
radios.forEach(r => {
r.onchange = function () {
try { localStorage.setItem('planning_machine_id', r.value); } catch (_) {}
};
});
});
});
</script>
{% endblock %}