713 lines
26 KiB
HTML
713 lines
26 KiB
HTML
{% extends "base.html" %}
|
|
{% block body_class %}page-bg bg-stock{% endblock %}
|
|
{% block content %}
|
|
<style>
|
|
body.bg-stock {
|
|
background-color: #B3B3DA;
|
|
background-image:
|
|
linear-gradient(rgba(179, 179, 218, 0.75), rgba(179, 179, 218, 0.75)),
|
|
url('{{ url_for("static", filename="bg/bg_sklad.png", v=1) }}');
|
|
background-size: auto 40vh;
|
|
}
|
|
.stock-section {
|
|
background: #B3B3DA;
|
|
border: 1px solid #B3B3DA;
|
|
box-shadow: none;
|
|
padding: 0.75rem;
|
|
margin-bottom: 1rem;
|
|
}
|
|
.stock-page .form-control,
|
|
.stock-page .form-select {
|
|
background-color: #ffffff;
|
|
border: 1px solid #B3B3DA;
|
|
}
|
|
.stock-page .form-control:focus,
|
|
.stock-page .form-select:focus {
|
|
box-shadow: 0 0 0 0.1rem rgba(0, 0, 0, 0.15);
|
|
border-color: #B3B3DA;
|
|
}
|
|
.stock-section h4 {
|
|
margin: 0 0 0.5rem 0;
|
|
font-size: 1rem;
|
|
}
|
|
.stock-form-grid {
|
|
display: grid;
|
|
grid-template-columns: 1fr 1fr;
|
|
gap: 0.6rem 1rem;
|
|
}
|
|
.stock-add-grid {
|
|
display: grid;
|
|
grid-template-columns: 1.2fr 0.9fr 1.2fr 1fr 1.2fr;
|
|
gap: 0.6rem 1rem;
|
|
grid-template-areas:
|
|
"inv type brand model serial"
|
|
"condition condition condition status status";
|
|
align-items: end;
|
|
}
|
|
.stock-add-field {
|
|
min-width: 0;
|
|
}
|
|
.stock-add-inv { grid-area: inv; }
|
|
.stock-add-type { grid-area: type; }
|
|
.stock-add-brand { grid-area: brand; }
|
|
.stock-add-model { grid-area: model; }
|
|
.stock-add-serial { grid-area: serial; }
|
|
.stock-add-condition { grid-area: condition; }
|
|
.stock-add-status { grid-area: status; }
|
|
@media (max-width: 980px) {
|
|
.stock-add-grid {
|
|
grid-template-columns: 1fr 1fr;
|
|
grid-template-areas:
|
|
"inv inv"
|
|
"type brand"
|
|
"model serial"
|
|
"condition condition"
|
|
"status status";
|
|
}
|
|
}
|
|
@media (max-width: 620px) {
|
|
.stock-add-grid {
|
|
grid-template-columns: 1fr;
|
|
grid-template-areas:
|
|
"inv"
|
|
"type"
|
|
"brand"
|
|
"model"
|
|
"serial"
|
|
"condition"
|
|
"status";
|
|
}
|
|
}
|
|
.stock-form-grid .full {
|
|
grid-column: 1 / -1;
|
|
}
|
|
.stock-add-grid .full {
|
|
grid-column: 1 / -1;
|
|
}
|
|
.stock-form-actions {
|
|
display: flex;
|
|
gap: 0.5rem;
|
|
margin-top: 0.5rem;
|
|
}
|
|
.stock-table {
|
|
width: 100%;
|
|
border-collapse: collapse;
|
|
}
|
|
.stock-table th,
|
|
.stock-table td {
|
|
border: 1px solid #b5b5b5;
|
|
padding: 0.35rem 0.5rem;
|
|
font-size: 0.92rem;
|
|
}
|
|
.stock-table th {
|
|
background: #d9d9d9;
|
|
font-weight: 600;
|
|
}
|
|
.row-actions {
|
|
background: #f8f9fa;
|
|
}
|
|
.row-actions__inner {
|
|
max-height: 0;
|
|
opacity: 0;
|
|
transform: translateY(-6px);
|
|
transition: max-height 0.2s ease, opacity 0.2s ease, transform 0.2s ease;
|
|
overflow: hidden;
|
|
padding: 0 0.75rem;
|
|
}
|
|
.row-actions.show .row-actions__inner {
|
|
max-height: 60px;
|
|
opacity: 1;
|
|
transform: translateY(0);
|
|
}
|
|
.edit-modal {
|
|
position: fixed;
|
|
inset: 0;
|
|
background: rgba(15, 23, 32, 0.55);
|
|
display: none;
|
|
align-items: center;
|
|
justify-content: center;
|
|
z-index: 1050;
|
|
padding: 1rem;
|
|
}
|
|
.edit-modal.show {
|
|
display: flex;
|
|
}
|
|
.edit-modal__dialog {
|
|
background: #fff;
|
|
border-radius: 0.75rem;
|
|
width: min(900px, 100%);
|
|
max-height: 85vh;
|
|
overflow: auto;
|
|
}
|
|
.edit-modal__header {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
padding: 0.75rem 1rem;
|
|
border-bottom: 1px solid #e2e2e2;
|
|
}
|
|
.edit-modal__title {
|
|
margin: 0;
|
|
font-size: 1.05rem;
|
|
}
|
|
.edit-modal__footer {
|
|
display: flex;
|
|
justify-content: flex-end;
|
|
gap: 0.5rem;
|
|
padding: 0.75rem 1rem;
|
|
border-top: 1px solid #e2e2e2;
|
|
}
|
|
.stock-note {
|
|
font-size: 0.85rem;
|
|
color: #555;
|
|
}
|
|
.specs-panel {
|
|
display: none;
|
|
margin-top: 0.6rem;
|
|
padding: 0;
|
|
border: none;
|
|
background: transparent;
|
|
}
|
|
.specs-panel.active {
|
|
display: block;
|
|
}
|
|
.stock-specs-grid {
|
|
display: grid;
|
|
grid-template-columns: 1.05fr 1.05fr 1.05fr 0.9fr 0.9fr 0.9fr;
|
|
gap: 0.6rem 1rem;
|
|
align-items: end;
|
|
}
|
|
@media (max-width: 980px) {
|
|
.stock-specs-grid {
|
|
grid-template-columns: 1fr 1fr;
|
|
}
|
|
}
|
|
@media (max-width: 620px) {
|
|
.stock-specs-grid {
|
|
grid-template-columns: 1fr;
|
|
}
|
|
}
|
|
</style>
|
|
|
|
<div class="stock-page">
|
|
<h3>{{ stock_view_title or 'Склад' }}</h3>
|
|
<div class="stock-section">
|
|
<h4>Добавить запись</h4>
|
|
<form method="post" action="/stock/add">
|
|
<div class="stock-add-grid">
|
|
<div class="stock-add-field stock-add-inv">
|
|
<label class="form-label">Инвентарный номер</label>
|
|
<input class="form-control" name="inventory_number">
|
|
</div>
|
|
<div class="stock-add-field stock-add-type">
|
|
<label class="form-label">Тип</label>
|
|
<select class="form-select" name="type" id="stockType">
|
|
<option value="">Выберите тип</option>
|
|
<option value="pc">ПК/Ноутбуки</option>
|
|
<option value="printers">МФУ/Принтеры</option>
|
|
<option value="projectors">Проекторы</option>
|
|
<option value="boards">Доски</option>
|
|
<option value="doc_cameras">Документ-камеры</option>
|
|
<option value="other">Остальное</option>
|
|
</select>
|
|
</div>
|
|
<div class="stock-add-field stock-add-brand">
|
|
<label class="form-label">Бренд</label>
|
|
<input class="form-control" name="brand">
|
|
</div>
|
|
<div class="stock-add-field stock-add-model">
|
|
<label class="form-label">Модель</label>
|
|
<input class="form-control" name="model">
|
|
</div>
|
|
<div class="stock-add-field stock-add-serial">
|
|
<label class="form-label">Серийный номер</label>
|
|
<input class="form-control" name="serial_number">
|
|
</div>
|
|
<div class="stock-add-field stock-add-condition">
|
|
<label class="form-label">Состояние</label>
|
|
<input class="form-control" name="condition">
|
|
</div>
|
|
<div class="stock-add-field stock-add-status">
|
|
<label class="form-label">Статус</label>
|
|
<select class="form-select" name="status">
|
|
<option value="">Выберите статус</option>
|
|
<option value="Действующий">Действующий</option>
|
|
<option value="Списан">Списан</option>
|
|
</select>
|
|
</div>
|
|
<div class="full">
|
|
<button type="button" class="btn btn-sm btn-outline-secondary" id="specsBtn" style="display:none;">
|
|
Характеристики
|
|
</button>
|
|
<div class="specs-panel" id="specsPanel">
|
|
<div class="stock-specs-grid">
|
|
<div>
|
|
<label class="form-label">Бренд CPU</label>
|
|
<select class="form-select" name="cpu_brand">
|
|
<option value="">Выберите бренд</option>
|
|
<option value="Intel">Intel</option>
|
|
<option value="AMD">AMD</option>
|
|
</select>
|
|
</div>
|
|
<div>
|
|
<label class="form-label">CPU</label>
|
|
<input class="form-control" name="cpu_model">
|
|
</div>
|
|
<div>
|
|
<label class="form-label">GPU</label>
|
|
<input class="form-control" name="gpu_model">
|
|
<input type="hidden" name="gpu_brand" value="">
|
|
</div>
|
|
<div>
|
|
<label class="form-label">Объем памяти</label>
|
|
<input class="form-control" name="memory_size">
|
|
</div>
|
|
<div>
|
|
<label class="form-label">Тип памяти</label>
|
|
<select class="form-select" name="memory_type">
|
|
<option value="">Выберите тип</option>
|
|
<option value="DDR">DDR</option>
|
|
<option value="DDR-2">DDR-2</option>
|
|
<option value="DDR-3">DDR-3</option>
|
|
<option value="DDR-4">DDR-4</option>
|
|
<option value="DDR-5">DDR-5</option>
|
|
</select>
|
|
</div>
|
|
<div>
|
|
<label class="form-label">Объем накопителя</label>
|
|
<input class="form-control" name="storage_size">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="stock-form-actions">
|
|
<button class="btn btn-sm btn-primary" type="submit">Добавить</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
|
|
<div class="stock-section">
|
|
<h4>ПК/Ноутбуки</h4>
|
|
<table class="stock-table">
|
|
<tr><th>Инвентарный номер</th><th>Тип</th><th>Бренд</th><th>Модель</th><th>Серийный номер</th><th>Состояние</th><th>Статус</th></tr>
|
|
{% for sid, inv, itype, brand, model, serial, condition, status, cpu_brand, cpu_model, gpu_brand, gpu_model, memory_size, memory_type, storage_size in items.get('pc', []) %}
|
|
<tr class="js-stock-row"
|
|
data-id="{{ sid }}"
|
|
data-inventory-number="{{ inv or '' }}"
|
|
data-type="{{ itype }}"
|
|
data-brand="{{ brand or '' }}"
|
|
data-model="{{ model or '' }}"
|
|
data-serial-number="{{ serial or '' }}"
|
|
data-condition="{{ condition or '' }}"
|
|
data-status="{{ status or '' }}"
|
|
data-cpu-brand="{{ cpu_brand or '' }}"
|
|
data-cpu-model="{{ cpu_model or '' }}"
|
|
data-gpu-brand="{{ gpu_brand or '' }}"
|
|
data-gpu-model="{{ gpu_model or '' }}"
|
|
data-memory-size="{{ memory_size or '' }}"
|
|
data-memory-type="{{ memory_type or '' }}"
|
|
data-storage-size="{{ storage_size or '' }}">
|
|
<td>{{ inv }}</td>
|
|
<td>ПК/Ноутбуки</td>
|
|
<td>{{ brand }}</td>
|
|
<td>{{ model }}</td>
|
|
<td>{{ serial }}</td>
|
|
<td>{{ condition }}</td>
|
|
<td>{{ status }}</td>
|
|
</tr>
|
|
{% else %}
|
|
<tr><td colspan="7" class="stock-note">Записей нет</td></tr>
|
|
{% endfor %}
|
|
</table>
|
|
</div>
|
|
|
|
<div class="stock-section">
|
|
<h4>МФУ/Принтеры</h4>
|
|
<table class="stock-table">
|
|
<tr><th>Инвентарный номер</th><th>Тип</th><th>Бренд</th><th>Модель</th><th>Серийный номер</th><th>Состояние</th><th>Статус</th></tr>
|
|
{% for sid, inv, itype, brand, model, serial, condition, status, cpu_brand, cpu_model, gpu_brand, gpu_model, memory_size, memory_type, storage_size in items.get('printers', []) %}
|
|
<tr class="js-stock-row"
|
|
data-id="{{ sid }}"
|
|
data-inventory-number="{{ inv or '' }}"
|
|
data-type="{{ itype }}"
|
|
data-brand="{{ brand or '' }}"
|
|
data-model="{{ model or '' }}"
|
|
data-serial-number="{{ serial or '' }}"
|
|
data-condition="{{ condition or '' }}"
|
|
data-status="{{ status or '' }}"
|
|
data-cpu-brand="{{ cpu_brand or '' }}"
|
|
data-cpu-model="{{ cpu_model or '' }}"
|
|
data-gpu-brand="{{ gpu_brand or '' }}"
|
|
data-gpu-model="{{ gpu_model or '' }}"
|
|
data-memory-size="{{ memory_size or '' }}"
|
|
data-memory-type="{{ memory_type or '' }}"
|
|
data-storage-size="{{ storage_size or '' }}">
|
|
<td>{{ inv }}</td>
|
|
<td>МФУ/Принтеры</td>
|
|
<td>{{ brand }}</td>
|
|
<td>{{ model }}</td>
|
|
<td>{{ serial }}</td>
|
|
<td>{{ condition }}</td>
|
|
<td>{{ status }}</td>
|
|
</tr>
|
|
{% else %}
|
|
<tr><td colspan="7" class="stock-note">Записей нет</td></tr>
|
|
{% endfor %}
|
|
</table>
|
|
</div>
|
|
|
|
<div class="stock-section">
|
|
<h4>Проекторы</h4>
|
|
<table class="stock-table">
|
|
<tr><th>Инвентарный номер</th><th>Тип</th><th>Бренд</th><th>Модель</th><th>Серийный номер</th><th>Состояние</th><th>Статус</th></tr>
|
|
{% for sid, inv, itype, brand, model, serial, condition, status, cpu_brand, cpu_model, gpu_brand, gpu_model, memory_size, memory_type, storage_size in items.get('projectors', []) %}
|
|
<tr class="js-stock-row"
|
|
data-id="{{ sid }}"
|
|
data-inventory-number="{{ inv or '' }}"
|
|
data-type="{{ itype }}"
|
|
data-brand="{{ brand or '' }}"
|
|
data-model="{{ model or '' }}"
|
|
data-serial-number="{{ serial or '' }}"
|
|
data-condition="{{ condition or '' }}"
|
|
data-status="{{ status or '' }}"
|
|
data-cpu-brand="{{ cpu_brand or '' }}"
|
|
data-cpu-model="{{ cpu_model or '' }}"
|
|
data-gpu-brand="{{ gpu_brand or '' }}"
|
|
data-gpu-model="{{ gpu_model or '' }}"
|
|
data-memory-size="{{ memory_size or '' }}"
|
|
data-memory-type="{{ memory_type or '' }}"
|
|
data-storage-size="{{ storage_size or '' }}">
|
|
<td>{{ inv }}</td>
|
|
<td>Проекторы</td>
|
|
<td>{{ brand }}</td>
|
|
<td>{{ model }}</td>
|
|
<td>{{ serial }}</td>
|
|
<td>{{ condition }}</td>
|
|
<td>{{ status }}</td>
|
|
</tr>
|
|
{% else %}
|
|
<tr><td colspan="7" class="stock-note">Записей нет</td></tr>
|
|
{% endfor %}
|
|
</table>
|
|
</div>
|
|
|
|
<div class="stock-section">
|
|
<h4>Доски</h4>
|
|
<table class="stock-table">
|
|
<tr><th>Инвентарный номер</th><th>Тип</th><th>Бренд</th><th>Модель</th><th>Серийный номер</th><th>Состояние</th><th>Статус</th></tr>
|
|
{% for sid, inv, itype, brand, model, serial, condition, status, cpu_brand, cpu_model, gpu_brand, gpu_model, memory_size, memory_type, storage_size in items.get('boards', []) %}
|
|
<tr class="js-stock-row"
|
|
data-id="{{ sid }}"
|
|
data-inventory-number="{{ inv or '' }}"
|
|
data-type="{{ itype }}"
|
|
data-brand="{{ brand or '' }}"
|
|
data-model="{{ model or '' }}"
|
|
data-serial-number="{{ serial or '' }}"
|
|
data-condition="{{ condition or '' }}"
|
|
data-status="{{ status or '' }}"
|
|
data-cpu-brand="{{ cpu_brand or '' }}"
|
|
data-cpu-model="{{ cpu_model or '' }}"
|
|
data-gpu-brand="{{ gpu_brand or '' }}"
|
|
data-gpu-model="{{ gpu_model or '' }}"
|
|
data-memory-size="{{ memory_size or '' }}"
|
|
data-memory-type="{{ memory_type or '' }}"
|
|
data-storage-size="{{ storage_size or '' }}">
|
|
<td>{{ inv }}</td>
|
|
<td>Доски</td>
|
|
<td>{{ brand }}</td>
|
|
<td>{{ model }}</td>
|
|
<td>{{ serial }}</td>
|
|
<td>{{ condition }}</td>
|
|
<td>{{ status }}</td>
|
|
</tr>
|
|
{% else %}
|
|
<tr><td colspan="7" class="stock-note">Записей нет</td></tr>
|
|
{% endfor %}
|
|
</table>
|
|
</div>
|
|
|
|
<div class="stock-section">
|
|
<h4>Документ-камеры</h4>
|
|
<table class="stock-table">
|
|
<tr><th>Инвентарный номер</th><th>Тип</th><th>Бренд</th><th>Модель</th><th>Серийный номер</th><th>Состояние</th><th>Статус</th></tr>
|
|
{% for sid, inv, itype, brand, model, serial, condition, status, cpu_brand, cpu_model, gpu_brand, gpu_model, memory_size, memory_type, storage_size in items.get('doc_cameras', []) %}
|
|
<tr class="js-stock-row"
|
|
data-id="{{ sid }}"
|
|
data-inventory-number="{{ inv or '' }}"
|
|
data-type="{{ itype }}"
|
|
data-brand="{{ brand or '' }}"
|
|
data-model="{{ model or '' }}"
|
|
data-serial-number="{{ serial or '' }}"
|
|
data-condition="{{ condition or '' }}"
|
|
data-status="{{ status or '' }}"
|
|
data-cpu-brand="{{ cpu_brand or '' }}"
|
|
data-cpu-model="{{ cpu_model or '' }}"
|
|
data-gpu-brand="{{ gpu_brand or '' }}"
|
|
data-gpu-model="{{ gpu_model or '' }}"
|
|
data-memory-size="{{ memory_size or '' }}"
|
|
data-memory-type="{{ memory_type or '' }}"
|
|
data-storage-size="{{ storage_size or '' }}">
|
|
<td>{{ inv }}</td>
|
|
<td>Документ-камеры</td>
|
|
<td>{{ brand }}</td>
|
|
<td>{{ model }}</td>
|
|
<td>{{ serial }}</td>
|
|
<td>{{ condition }}</td>
|
|
<td>{{ status }}</td>
|
|
</tr>
|
|
{% else %}
|
|
<tr><td colspan="7" class="stock-note">Записей нет</td></tr>
|
|
{% endfor %}
|
|
</table>
|
|
</div>
|
|
|
|
<div class="stock-section">
|
|
<h4>Остальное</h4>
|
|
<table class="stock-table">
|
|
<tr><th>Инвентарный номер</th><th>Тип</th><th>Бренд</th><th>Модель</th><th>Серийный номер</th><th>Состояние</th><th>Статус</th></tr>
|
|
{% for sid, inv, itype, brand, model, serial, condition, status, cpu_brand, cpu_model, gpu_brand, gpu_model, memory_size, memory_type, storage_size in items.get('other', []) %}
|
|
<tr class="js-stock-row"
|
|
data-id="{{ sid }}"
|
|
data-inventory-number="{{ inv or '' }}"
|
|
data-type="{{ itype }}"
|
|
data-brand="{{ brand or '' }}"
|
|
data-model="{{ model or '' }}"
|
|
data-serial-number="{{ serial or '' }}"
|
|
data-condition="{{ condition or '' }}"
|
|
data-status="{{ status or '' }}"
|
|
data-cpu-brand="{{ cpu_brand or '' }}"
|
|
data-cpu-model="{{ cpu_model or '' }}"
|
|
data-gpu-brand="{{ gpu_brand or '' }}"
|
|
data-gpu-model="{{ gpu_model or '' }}"
|
|
data-memory-size="{{ memory_size or '' }}"
|
|
data-memory-type="{{ memory_type or '' }}"
|
|
data-storage-size="{{ storage_size or '' }}">
|
|
<td>{{ inv }}</td>
|
|
<td>Остальное</td>
|
|
<td>{{ brand }}</td>
|
|
<td>{{ model }}</td>
|
|
<td>{{ serial }}</td>
|
|
<td>{{ condition }}</td>
|
|
<td>{{ status }}</td>
|
|
</tr>
|
|
{% else %}
|
|
<tr><td colspan="7" class="stock-note">Записей нет</td></tr>
|
|
{% endfor %}
|
|
</table>
|
|
</div>
|
|
|
|
{% if session.get('role') in ('admin','storekeeper') %}
|
|
<div class="edit-modal" id="stockEditModal" aria-hidden="true">
|
|
<div class="edit-modal__dialog">
|
|
<div class="edit-modal__header">
|
|
<h4 class="edit-modal__title">Редактирование записи склада</h4>
|
|
<button type="button" class="btn btn-sm btn-outline-secondary" data-modal-close>Закрыть</button>
|
|
</div>
|
|
<form method="post" action="/stock/edit" id="stockEditForm">
|
|
<input type="hidden" name="id" id="stockModalId">
|
|
<div class="row g-2">
|
|
<div class="col-md-3">
|
|
<input name="inventory_number" id="stockModalInv" class="form-control" placeholder="Инв. №">
|
|
</div>
|
|
<div class="col-md-3">
|
|
<select name="type" id="stockModalType" class="form-select">
|
|
<option value="">Тип...</option>
|
|
<option value="pc">ПК/Ноутбуки</option>
|
|
<option value="printers">МФУ/Принтеры</option>
|
|
<option value="projectors">Проекторы</option>
|
|
<option value="boards">Доски</option>
|
|
<option value="doc_cameras">Документ-камеры</option>
|
|
<option value="other">Остальное</option>
|
|
</select>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<input name="brand" id="stockModalBrand" class="form-control" placeholder="Бренд">
|
|
</div>
|
|
<div class="col-md-3">
|
|
<input name="model" id="stockModalModel" class="form-control" placeholder="Модель">
|
|
</div>
|
|
<div class="col-md-3">
|
|
<input name="serial_number" id="stockModalSerial" class="form-control" placeholder="Серийный №">
|
|
</div>
|
|
<div class="col-md-3">
|
|
<input name="condition" id="stockModalCondition" class="form-control" placeholder="Состояние">
|
|
</div>
|
|
<div class="col-md-3">
|
|
<select name="status" id="stockModalStatus" class="form-select">
|
|
<option value="">Статус...</option>
|
|
<option value="Действующий">Действующий</option>
|
|
<option value="Списан">Списан</option>
|
|
</select>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<select name="cpu_brand" id="stockModalCpuBrand" class="form-select">
|
|
<option value="">Бренд CPU...</option>
|
|
<option value="Intel">Intel</option>
|
|
<option value="AMD">AMD</option>
|
|
</select>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<input name="cpu_model" id="stockModalCpuModel" class="form-control" placeholder="CPU">
|
|
</div>
|
|
<div class="col-md-3">
|
|
<input name="gpu_model" id="stockModalGpuModel" class="form-control" placeholder="GPU">
|
|
<input type="hidden" name="gpu_brand" id="stockModalGpuBrand">
|
|
</div>
|
|
<div class="col-md-3">
|
|
<input name="memory_size" id="stockModalMemorySize" class="form-control" placeholder="Память">
|
|
</div>
|
|
<div class="col-md-3">
|
|
<select name="memory_type" id="stockModalMemoryType" class="form-select">
|
|
<option value="">Тип памяти...</option>
|
|
<option value="DDR">DDR</option>
|
|
<option value="DDR-2">DDR-2</option>
|
|
<option value="DDR-3">DDR-3</option>
|
|
<option value="DDR-4">DDR-4</option>
|
|
<option value="DDR-5">DDR-5</option>
|
|
</select>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<input name="storage_size" id="stockModalStorageSize" class="form-control" placeholder="Накопитель">
|
|
</div>
|
|
</div>
|
|
<div class="edit-modal__footer">
|
|
<button type="button" class="btn btn-outline-secondary" data-modal-close>Отмена</button>
|
|
<button class="btn btn-primary">Сохранить</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
|
|
<script>
|
|
(function() {
|
|
const typeSelect = document.getElementById('stockType');
|
|
const specsBtn = document.getElementById('specsBtn');
|
|
const specsPanel = document.getElementById('specsPanel');
|
|
if (!typeSelect || !specsBtn || !specsPanel) return;
|
|
|
|
function syncSpecs() {
|
|
const isPc = typeSelect.value === 'pc';
|
|
specsBtn.style.display = isPc ? 'inline-block' : 'none';
|
|
if (!isPc) specsPanel.classList.remove('active');
|
|
}
|
|
|
|
specsBtn.addEventListener('click', () => {
|
|
specsPanel.classList.toggle('active');
|
|
});
|
|
typeSelect.addEventListener('change', syncSpecs);
|
|
syncSpecs();
|
|
})();
|
|
</script>
|
|
<script>
|
|
(function() {
|
|
const canEdit = {{ 'true' if session.get('role') in ('admin','storekeeper') else 'false' }};
|
|
if (!canEdit) return;
|
|
const rows = document.querySelectorAll('.js-stock-row');
|
|
if (!rows.length) return;
|
|
const modal = document.getElementById('stockEditModal');
|
|
const form = document.getElementById('stockEditForm');
|
|
if (!modal || !form) return;
|
|
|
|
const modalFields = {
|
|
id: document.getElementById('stockModalId'),
|
|
inventory_number: document.getElementById('stockModalInv'),
|
|
type: document.getElementById('stockModalType'),
|
|
brand: document.getElementById('stockModalBrand'),
|
|
model: document.getElementById('stockModalModel'),
|
|
serial_number: document.getElementById('stockModalSerial'),
|
|
condition: document.getElementById('stockModalCondition'),
|
|
status: document.getElementById('stockModalStatus'),
|
|
cpu_brand: document.getElementById('stockModalCpuBrand'),
|
|
cpu_model: document.getElementById('stockModalCpuModel'),
|
|
gpu_brand: document.getElementById('stockModalGpuBrand'),
|
|
gpu_model: document.getElementById('stockModalGpuModel'),
|
|
memory_size: document.getElementById('stockModalMemorySize'),
|
|
memory_type: document.getElementById('stockModalMemoryType'),
|
|
storage_size: document.getElementById('stockModalStorageSize'),
|
|
};
|
|
|
|
function closeModal() {
|
|
modal.classList.remove('show');
|
|
modal.setAttribute('aria-hidden', 'true');
|
|
}
|
|
|
|
function openModal() {
|
|
modal.classList.add('show');
|
|
modal.setAttribute('aria-hidden', 'false');
|
|
}
|
|
|
|
modal.addEventListener('click', (e) => {
|
|
if (e.target === modal || e.target.hasAttribute('data-modal-close')) {
|
|
closeModal();
|
|
}
|
|
});
|
|
|
|
function fillModalFromRow(row) {
|
|
const map = [
|
|
"id",
|
|
"inventory_number",
|
|
"type",
|
|
"brand",
|
|
"model",
|
|
"serial_number",
|
|
"condition",
|
|
"status",
|
|
"cpu_brand",
|
|
"cpu_model",
|
|
"gpu_brand",
|
|
"gpu_model",
|
|
"memory_size",
|
|
"memory_type",
|
|
"storage_size",
|
|
];
|
|
map.forEach((name) => {
|
|
if (!modalFields[name]) return;
|
|
const dataKey = name.replace(/_/g, '-');
|
|
const attrValue = row.getAttribute(`data-${dataKey}`);
|
|
if (attrValue !== null) {
|
|
modalFields[name].value = attrValue || '';
|
|
}
|
|
});
|
|
return true;
|
|
}
|
|
|
|
function showActionRow(row) {
|
|
const existing = row.parentElement.querySelector('.row-actions');
|
|
if (existing) existing.remove();
|
|
const rowId = row.getAttribute('data-id') || '';
|
|
const actionRow = document.createElement('tr');
|
|
actionRow.className = 'row-actions';
|
|
actionRow.innerHTML = `<td colspan="7">
|
|
<div class="row-actions__inner">
|
|
<button type="button" class="btn btn-sm btn-outline-primary js-open-stock-modal">Редактировать</button>
|
|
<form method="post" action="/stock/delete" class="d-inline ms-2">
|
|
<input type="hidden" name="id" value="${rowId}">
|
|
<button class="btn btn-sm btn-outline-danger" type="submit">Удалить</button>
|
|
</form>
|
|
</div>
|
|
</td>`;
|
|
row.insertAdjacentElement('afterend', actionRow);
|
|
const btn = actionRow.querySelector('.js-open-stock-modal');
|
|
btn.addEventListener('click', () => {
|
|
if (fillModalFromRow(row)) openModal();
|
|
});
|
|
requestAnimationFrame(() => actionRow.classList.add('show'));
|
|
}
|
|
|
|
rows.forEach((row) => {
|
|
row.addEventListener('click', (e) => {
|
|
if (e.target.closest('button, input, select, textarea, a')) return;
|
|
showActionRow(row);
|
|
});
|
|
row.addEventListener('dblclick', (e) => {
|
|
if (e.target.closest('button, input, select, textarea, a')) return;
|
|
if (fillModalFromRow(row)) openModal();
|
|
});
|
|
});
|
|
})();
|
|
</script>
|
|
</div>
|
|
{% endblock %}
|