Обновлены поля: бюджет из Бюджет закупок, исполнение из Сумма поставки, экономия, тип бюджета БКВ/ОБ

This commit is contained in:
Rollan_Tuleuov 2026-08-18 10:11:12 +00:00
parent 56205d6cf4
commit f27a8b95de
2 changed files with 41 additions and 21 deletions

View File

@ -78,7 +78,7 @@
<div class="about-card"> <div class="about-card">
<div class="about-icon">📈</div> <div class="about-icon">📈</div>
<h3>Данные</h3> <h3>Данные</h3>
<p>Код статьи бюджета, наименование услуг/работ, подразделение-заказчик, плановые суммы и фактическое исполнение</p> <p>Краткий текст материала, подразделение (МВЗ), тип бюджета (БКВ/ОБ), бюджет закупок, сумма поставки, экономия</p>
</div> </div>
<div class="about-card"> <div class="about-card">
<div class="about-icon">🎯</div> <div class="about-icon">🎯</div>
@ -117,11 +117,12 @@
<table> <table>
<thead> <thead>
<tr> <tr>
<th onclick="sort('articleCode')">Код статьи ↕</th> <th onclick="sort('serviceName')">Наименование ↕</th>
<th onclick="sort('serviceName')">Наименование услуги ↕</th>
<th onclick="sort('department')">Подразделение ↕</th> <th onclick="sort('department')">Подразделение ↕</th>
<th class="amount" onclick="sort('budgetSum')">Бюджет ↕</th> <th onclick="sort('budgetType')">Тип бюджета ↕</th>
<th class="amount" onclick="sort('executedSum')">Исполнено ↕</th> <th class="amount" onclick="sort('budgetSum')">Бюджет закупок, тг ↕</th>
<th class="amount" onclick="sort('executedSum')">Сумма поставки, тг ↕</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> <th onclick="sort('status')">Статус ↕</th>
</tr> </tr>
@ -180,14 +181,19 @@
function renderStats() { function renderStats() {
const totalBudget = allData.reduce((sum, r) => sum + (r.budgetSum || 0), 0); const totalBudget = allData.reduce((sum, r) => sum + (r.budgetSum || 0), 0);
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 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 fullyExecuted = allData.filter(r => r.execPercent >= 95).length;
const bkvCount = allData.filter(r => r.budgetType === 'БКВ').length;
const obCount = allData.filter(r => r.budgetType === 'ОБ').length;
document.getElementById('stats').innerHTML = document.getElementById('stats').innerHTML =
'<div class="stat-card"><div class="value">' + formatAmount(totalBudget) + '</div><div class="label">Всего бюджет</div></div>' + '<div class="stat-card"><div class="value">' + formatAmount(totalBudget) + '</div><div class="label">Бюджет закупок, тг</div></div>' +
'<div class="stat-card"><div class="value">' + formatAmount(totalExecuted) + '</div><div class="label">Исполнено</div></div>' + '<div class="stat-card"><div class="value">' + formatAmount(totalExecuted) + '</div><div class="label">Сумма поставки, тг</div></div>' +
'<div class="stat-card"><div class="value">' + formatAmount(totalEconomy) + '</div><div class="label">Экономия, тг</div></div>' +
'<div class="stat-card"><div class="value">' + formatAmount(avgPercent) + '%</div><div class="label">Среднее исполнение</div></div>' + '<div class="stat-card"><div class="value">' + formatAmount(avgPercent) + '%</div><div class="label">Среднее исполнение</div></div>' +
'<div class="stat-card"><div class="value">' + fullyExecuted + '</div><div class="label">Полностью исполнено</div></div>'; '<div class="stat-card"><div class="value">' + bkvCount + '</div><div class="label">БКВ</div></div>' +
'<div class="stat-card"><div class="value">' + obCount + '</div><div class="label">ОБ</div></div>';
} }
function renderTable() { function renderTable() {
@ -205,11 +211,12 @@
const statusClass = getStatusClass(r.execPercent || 0); const statusClass = getStatusClass(r.execPercent || 0);
const statusText = getStatusText(r.execPercent || 0); const statusText = getStatusText(r.execPercent || 0);
return '<tr>' + return '<tr>' +
'<td>' + (r.articleCode || '-') + '</td>' +
'<td>' + (r.serviceName || '-') + '</td>' + '<td>' + (r.serviceName || '-') + '</td>' +
'<td>' + (r.department || '-') + '</td>' + '<td>' + (r.department || '-') + '</td>' +
'<td>' + (r.budgetType || '-') + '</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="percent">' + formatAmount(r.execPercent || 0) + '%</td>' + '<td class="percent">' + formatAmount(r.execPercent || 0) + '%</td>' +
'<td><span class="status-badge ' + statusClass + '">' + statusText + '</span></td>' + '<td><span class="status-badge ' + statusClass + '">' + statusText + '</span></td>' +
'</tr>'; '</tr>';
@ -297,13 +304,14 @@
} }
function exportToExcel() { function exportToExcel() {
const head = ["Код статьи", "Наименование услуги", "Подразделение", "Бюджет", "Исполнено", "Исполнение %", "Статус"]; const head = ["Наименование", "Подразделение", "Тип бюджета", "Бюджет закупок, тг", "Сумма поставки, тг", "Экономия, тг", "Исполнение %", "Статус"];
const body = filteredData.map(r => [ const body = filteredData.map(r => [
r.articleCode || '',
r.serviceName || '', r.serviceName || '',
r.department || '', r.department || '',
r.budgetType || '',
r.budgetSum || 0, r.budgetSum || 0,
r.executedSum || 0, r.executedSum || 0,
r.economy || 0,
(r.execPercent || 0).toFixed(2), (r.execPercent || 0).toFixed(2),
getStatusText(r.execPercent || 0) getStatusText(r.execPercent || 0)
]); ]);

View File

@ -25,18 +25,19 @@ function parseExcelData() {
const findColumn = (names) => { const findColumn = (names) => {
for (const name of names) { for (const name of names) {
const idx = headers.findIndex(h => h.includes(name.toLowerCase())); const idx = headers.findIndex(h => h.toLowerCase().includes(name.toLowerCase()));
if (idx !== -1) return idx; if (idx !== -1) return idx;
} }
return -1; return -1;
}; };
const articleCodeIdx = findColumn(['код статьи', 'статья', 'код']); const serviceNameIdx = findColumn(['Краткий текст материала']);
const serviceNameIdx = findColumn(['наименование', 'услуг', 'работ', 'название']); const budgetSumIdx = findColumn(['Бюджет закупок,тг']);
const departmentIdx = findColumn(['подраздел', 'центр', 'департамент', 'управление']); const executedSumIdx = findColumn(['Сумма поставки,тг']);
const budgetSumIdx = findColumn(['бюджет', 'план', 'сумма план']); const economyIdx = findColumn(['Экономия от проведенного закупа']);
const executedSumIdx = findColumn(['исполн', 'факт', 'оплачено']); const sppElementIdx = findColumn(['СПП-элемент']);
const execPercentIdx = findColumn(['исполнение', '%', 'процент']); const departmentIdx = findColumn(['Завод', 'МВЗ', 'Текст МВЗ']);
const execPercentIdx = findColumn(['% исполнения']);
const data = []; const data = [];
for (let i = 1; i < rows.length; i++) { for (let i = 1; i < rows.length; i++) {
@ -45,8 +46,17 @@ 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;
let execPercent = 0; const economy = parseFloat(String(row[economyIdx] || 0).replace(/\s/g, '')) || 0;
const sppElement = String(row[sppElementIdx] || '').trim();
let budgetType = '';
if (sppElement.startsWith('I')) {
budgetType = 'БКВ';
} else if (sppElement.startsWith('O')) {
budgetType = 'ОБ';
}
let execPercent = 0;
if (execPercentIdx !== -1 && row[execPercentIdx]) { if (execPercentIdx !== -1 && row[execPercentIdx]) {
execPercent = parseFloat(String(row[execPercentIdx]).replace('%', '').replace(/\s/g, '')) || 0; execPercent = parseFloat(String(row[execPercentIdx]).replace('%', '').replace(/\s/g, '')) || 0;
} else if (budgetSum > 0) { } else if (budgetSum > 0) {
@ -54,15 +64,17 @@ function parseExcelData() {
} }
const item = { const item = {
articleCode: String(row[articleCodeIdx] || '').trim(),
serviceName: String(row[serviceNameIdx] || '').trim(), serviceName: String(row[serviceNameIdx] || '').trim(),
department: String(row[departmentIdx] || '').trim(), department: String(row[departmentIdx] || '').trim(),
budgetType: budgetType,
sppElement: sppElement,
budgetSum: budgetSum, budgetSum: budgetSum,
executedSum: executedSum, executedSum: executedSum,
economy: economy,
execPercent: Math.round(execPercent * 100) / 100 execPercent: Math.round(execPercent * 100) / 100
}; };
if (item.serviceName || item.articleCode) { if (item.serviceName) {
data.push(item); data.push(item);
} }
} }