Добавлены фильтры: Способ закупки, Вид закупа, Тип бюджета

This commit is contained in:
Rollan_Tuleuov 2026-08-18 10:51:19 +00:00
parent b83855e578
commit 5f4a08bb1e
3 changed files with 1919 additions and 21 deletions

1866
data.json

File diff suppressed because it is too large Load Diff

View File

@ -102,12 +102,17 @@
<div class="filters"> <div class="filters">
<div class="filters-row"> <div class="filters-row">
<input type="text" id="searchInput" placeholder="Поиск по названию услуги, подразделению, статье..."> <input type="text" id="searchInput" placeholder="Поиск по названию услуги, подразделению...">
<select id="statusFilter"> <select id="procurementMethodFilter">
<option value="">Все статусы</option> <option value="">Все способы закупки</option>
<option value="100">100% исполнение</option> </select>
<option value="50-99">50-99% исполнение</option> <select id="procurementTypeFilter">
<option value="0-49">0-49% исполнение</option> <option value="">Все виды закупа</option>
</select>
<select id="budgetTypeFilter">
<option value="">Все типы бюджета</option>
<option value="БКВ">БКВ</option>
<option value="ОБ">ОБ</option>
</select> </select>
<button onclick="applyFilters()">Применить</button> <button onclick="applyFilters()">Применить</button>
<button class="secondary" onclick="resetFilters()">Сбросить</button> <button class="secondary" onclick="resetFilters()">Сбросить</button>
@ -121,11 +126,12 @@
<th onclick="sort('serviceName')">Наименование ↕</th> <th onclick="sort('serviceName')">Наименование ↕</th>
<th onclick="sort('department')">Подразделение ↕</th> <th onclick="sort('department')">Подразделение ↕</th>
<th onclick="sort('budgetType')">Тип бюджета ↕</th> <th onclick="sort('budgetType')">Тип бюджета ↕</th>
<th onclick="sort('procurementMethod')">Способ закупки ↕</th>
<th onclick="sort('procurementType')">Вид закупа ↕</th>
<th class="amount" onclick="sort('budgetSum')">Бюджет закупок, тг ↕</th> <th class="amount" onclick="sort('budgetSum')">Бюджет закупок, тг ↕</th>
<th class="amount" onclick="sort('executedSum')">Сумма поставки, тг ↕</th> <th class="amount" onclick="sort('executedSum')">Сумма поставки, тг ↕</th>
<th class="amount" onclick="sort('economy')">Экономия, тг ↕</th> <th class="amount" onclick="sort('economy')">Экономия, тг ↕</th>
<th class="percent" onclick="sort('execPercent')">Исполнение % ↕</th> <th class="percent" onclick="sort('execPercent')">Исполнение % ↕</th>
<th onclick="sort('status')">Статус ↕</th>
</tr> </tr>
</thead> </thead>
<tbody id="tableBody"></tbody> <tbody id="tableBody"></tbody>
@ -150,16 +156,39 @@
let currentSort = null; let currentSort = null;
let sortAsc = true; let sortAsc = true;
function populateFilters() {
const methods = [...new Set(allData.map(r => r.procurementMethod).filter(Boolean))].sort();
const types = [...new Set(allData.map(r => r.procurementType).filter(Boolean))].sort();
const methodSelect = document.getElementById('procurementMethodFilter');
const typeSelect = document.getElementById('procurementTypeFilter');
methods.forEach(m => {
const opt = document.createElement('option');
opt.value = m;
opt.textContent = m;
methodSelect.appendChild(opt);
});
types.forEach(t => {
const opt = document.createElement('option');
opt.value = t;
opt.textContent = t;
typeSelect.appendChild(opt);
});
}
async function loadData() { async function loadData() {
try { try {
const response = await fetch('data.json'); const response = await fetch('data.json');
allData = await response.json(); allData = await response.json();
filteredData = [...allData]; filteredData = [...allData];
populateFilters();
renderStats(); renderStats();
renderTable(); renderTable();
updatePagination(); updatePagination();
} catch (error) { } catch (error) {
document.getElementById('tableBody').innerHTML = '<tr><td colspan="7" class="loading">Ошибка загрузки данных: ' + error.message + '</td></tr>'; document.getElementById('tableBody').innerHTML = '<tr><td colspan="9" class="loading">Ошибка загрузки данных: ' + error.message + '</td></tr>';
} }
} }
@ -184,7 +213,6 @@
const totalExecuted = allData.reduce((sum, r) => sum + (r.executedSum || 0), 0); const totalExecuted = allData.reduce((sum, r) => sum + (r.executedSum || 0), 0);
const totalEconomy = allData.reduce((sum, r) => sum + (r.economy || 0), 0); const totalEconomy = allData.reduce((sum, r) => sum + (r.economy || 0), 0);
const avgPercent = totalBudget > 0 ? (totalExecuted / totalBudget) * 100 : 0; const avgPercent = totalBudget > 0 ? (totalExecuted / totalBudget) * 100 : 0;
const fullyExecuted = allData.filter(r => r.execPercent >= 95).length;
const bkvCount = allData.filter(r => r.budgetType === 'БКВ').length; const bkvCount = allData.filter(r => r.budgetType === 'БКВ').length;
const obCount = allData.filter(r => r.budgetType === 'ОБ').length; const obCount = allData.filter(r => r.budgetType === 'ОБ').length;
@ -209,17 +237,16 @@
} }
tbody.innerHTML = pageData.map(function(r) { tbody.innerHTML = pageData.map(function(r) {
const statusClass = getStatusClass(r.execPercent || 0);
const statusText = getStatusText(r.execPercent || 0);
return '<tr>' + return '<tr>' +
'<td>' + (r.serviceName || '-') + '</td>' + '<td>' + (r.serviceName || '-') + '</td>' +
'<td>' + (r.department || '-') + '</td>' + '<td>' + (r.department || '-') + '</td>' +
'<td>' + (r.budgetType || '-') + '</td>' + '<td>' + (r.budgetType || '-') + '</td>' +
'<td>' + (r.procurementMethod || '-') + '</td>' +
'<td>' + (r.procurementType || '-') + '</td>' +
'<td class="amount">' + formatAmount(r.budgetSum || 0) + '</td>' + '<td class="amount">' + formatAmount(r.budgetSum || 0) + '</td>' +
'<td class="amount">' + formatAmount(r.executedSum || 0) + '</td>' + '<td class="amount">' + formatAmount(r.executedSum || 0) + '</td>' +
'<td class="amount" style="color: ' + (r.economy > 0 ? '#22c55e' : '#666') + '">' + formatAmount(r.economy || 0) + '</td>' + '<td class="amount" style="color: ' + (r.economy > 0 ? '#22c55e' : '#666') + '">' + formatAmount(r.economy || 0) + '</td>' +
'<td class="percent">' + formatAmount(r.execPercent || 0) + '%</td>' + '<td class="percent">' + formatAmount(r.execPercent || 0) + '%</td>' +
'<td><span class="status-badge ' + statusClass + '">' + statusText + '</span></td>' +
'</tr>'; '</tr>';
}).join(''); }).join('');
} }
@ -236,20 +263,20 @@
function applyFilters() { function applyFilters() {
const search = document.getElementById('searchInput').value.toLowerCase(); const search = document.getElementById('searchInput').value.toLowerCase();
const status = document.getElementById('statusFilter').value; const procurementMethod = document.getElementById('procurementMethodFilter').value;
const procurementType = document.getElementById('procurementTypeFilter').value;
const budgetType = document.getElementById('budgetTypeFilter').value;
filteredData = allData.filter(function(r) { filteredData = allData.filter(function(r) {
const matchesSearch = !search || const matchesSearch = !search ||
(r.serviceName && r.serviceName.toLowerCase().includes(search)) || (r.serviceName && r.serviceName.toLowerCase().includes(search)) ||
(r.department && r.department.toLowerCase().includes(search)) || (r.department && r.department.toLowerCase().includes(search));
(r.articleCode && r.articleCode.toLowerCase().includes(search));
let matchesStatus = true; const matchesMethod = !procurementMethod || r.procurementMethod === procurementMethod;
if (status === '100') matchesStatus = r.execPercent >= 95; const matchesType = !procurementType || r.procurementType === procurementType;
else if (status === '50-99') matchesStatus = r.execPercent >= 50 && r.execPercent < 95; const matchesBudget = !budgetType || r.budgetType === budgetType;
else if (status === '0-49') matchesStatus = r.execPercent < 50;
return matchesSearch && matchesStatus; return matchesSearch && matchesMethod && matchesType && matchesBudget;
}); });
currentPage = 1; currentPage = 1;

View File

@ -36,7 +36,8 @@ function parseExcelData() {
const executedSumIdx = findColumn(['Сумма поставки,тг']); const executedSumIdx = findColumn(['Сумма поставки,тг']);
const sppElementIdx = findColumn(['СПП-элемент']); const sppElementIdx = findColumn(['СПП-элемент']);
const departmentIdx = findColumn(['Завод', 'МВЗ', 'Текст МВЗ']); const departmentIdx = findColumn(['Завод', 'МВЗ', 'Текст МВЗ']);
const execPercentIdx = findColumn(['% исполнения']); const procurementMethodIdx = findColumn(['Способ закупки']);
const procurementTypeIdx = findColumn(['Вид закупа']);
const data = []; const data = [];
for (let i = 1; i < rows.length; i++) { for (let i = 1; i < rows.length; i++) {
@ -46,6 +47,8 @@ function parseExcelData() {
const budgetSum = parseFloat(String(row[budgetSumIdx] || 0).replace(/\s/g, '')) || 0; const budgetSum = parseFloat(String(row[budgetSumIdx] || 0).replace(/\s/g, '')) || 0;
const executedSum = parseFloat(String(row[executedSumIdx] || 0).replace(/\s/g, '')) || 0; const executedSum = parseFloat(String(row[executedSumIdx] || 0).replace(/\s/g, '')) || 0;
const sppElement = String(row[sppElementIdx] || '').trim(); const sppElement = String(row[sppElementIdx] || '').trim();
const procurementMethod = String(row[procurementMethodIdx] || '').trim();
const procurementType = String(row[procurementTypeIdx] || '').trim();
// Экономия = Бюджет - Сумма поставки // Экономия = Бюджет - Сумма поставки
const economy = budgetSum - executedSum; const economy = budgetSum - executedSum;
@ -68,6 +71,8 @@ function parseExcelData() {
department: String(row[departmentIdx] || '').trim(), department: String(row[departmentIdx] || '').trim(),
budgetType: budgetType, budgetType: budgetType,
sppElement: sppElement, sppElement: sppElement,
procurementMethod: procurementMethod,
procurementType: procurementType,
budgetSum: budgetSum, budgetSum: budgetSum,
executedSum: executedSum, executedSum: executedSum,
economy: economy, economy: economy,