-
Найдено: 0 населённых пунктов
-
⬇ Скачать Excel
+
+
+
🔍 Фильтр и отбор
+
Выберите регион, отметьте нужные населённые пункты
+
+
+ ✅ Отмечено: 0
+ |
+ Всего: 0
+
+
+
+
+ Область
+ — Все —
+
+
+ Район
+ — Все —
+
+
+ Округ
+ — Все —
+
+
+ Только отмеченные
+
+
+
+
+ ✅ Отметить все в фильтре
+ ✕ Снять все
+
+ ⬇ Скачать только отмеченные
+
+
@@ -97,6 +143,8 @@ let allData = [];
let filteredData = [];
let dataColumns = [];
let hierarchy = {};
+let markedIds = new Set();
+let showMarkedOnly = false;
const COL_KEYWORDS = {
kato: ['като', 'код', 'katо', 'kato'],
@@ -114,8 +162,13 @@ function detectColumn(name) {
return null;
}
+function rowId(row, idx) {
+ const katoCol = dataColumns.indexOf('kato');
+ if (katoCol !== -1 && row[dataColumns[katoCol]]) return String(row[dataColumns[katoCol]]).trim();
+ return 'row_' + idx;
+}
+
function initHierarchy(data) {
- const katoIx = dataColumns.indexOf('kato') !== -1 ? dataColumns.indexOf('kato') : 0;
const obIx = dataColumns.indexOf('oblast');
const raIx = dataColumns.indexOf('rayon');
const okIx = dataColumns.indexOf('okrug');
@@ -145,96 +198,155 @@ function initHierarchy(data) {
}
function renderFilters() {
- const container = document.getElementById('filtersContainer');
- container.innerHTML = `
-
- Область / Регион
- — Все —
- ${hierarchy.oblasts.map(o => `${o} `).join('')}
-
-
-
- Район
- — Все —
-
-
- Округ
- — Все —
-
- `;
+ const selO = document.getElementById('filterOblast');
+ selO.innerHTML = '
— Все — ' + hierarchy.oblasts.map(o => `
${o} `).join('');
- const selOblast = document.getElementById('filterOblast');
- const selRayon = document.getElementById('filterRayon');
- const selOkrug = document.getElementById('filterOkrug');
-
- selOblast.addEventListener('change', () => {
- updateRayonOptions();
- selOkrug.innerHTML = '
— Все — ';
+ document.getElementById('filterOblast').onchange = () => {
+ const ob = selO.value;
+ const selR = document.getElementById('filterRayon');
+ selR.innerHTML = '
— Все — ' + (ob && hierarchy.rayons[ob] ? hierarchy.rayons[ob].map(r => `
${r} `).join('') : '');
+ document.getElementById('filterOkrug').innerHTML = '
— Все — ';
applyFilter();
- });
- selRayon.addEventListener('change', () => {
- updateOkrugOptions();
+ };
+
+ document.getElementById('filterRayon').onchange = () => {
+ const ob = selO.value, ra = document.getElementById('filterRayon').value;
+ const selK = document.getElementById('filterOkrug');
+ const key = ob + '|' + ra;
+ selK.innerHTML = '
— Все — ' + (ob && ra && hierarchy.okrugs[key] ? hierarchy.okrugs[key].map(o => `
${o} `).join('') : '');
applyFilter();
- });
- selOkrug.addEventListener('change', applyFilter);
-}
+ };
-function updateRayonOptions() {
- const ob = document.getElementById('filterOblast').value;
- const sel = document.getElementById('filterRayon');
- const rayons = ob && hierarchy.rayons[ob] ? hierarchy.rayons[ob] : [];
- sel.innerHTML = '
— Все — ' + rayons.map(r => `
${r} `).join('');
-}
-
-function updateOkrugOptions() {
- const ob = document.getElementById('filterOblast').value;
- const ra = document.getElementById('filterRayon').value;
- const sel = document.getElementById('filterOkrug');
- const key = ob + '|' + ra;
- const okrugs = ob && ra && hierarchy.okrugs[key] ? hierarchy.okrugs[key] : [];
- sel.innerHTML = '
— Все — ' + okrugs.map(o => `
${o} `).join('');
+ document.getElementById('filterOkrug').onchange = applyFilter;
+ document.getElementById('showMarkedOnly').onchange = () => {
+ showMarkedOnly = document.getElementById('showMarkedOnly').checked;
+ applyFilter();
+ };
}
function applyFilter() {
const ob = document.getElementById('filterOblast').value;
const ra = document.getElementById('filterRayon').value;
const ok = document.getElementById('filterOkrug').value;
-
const obIx = dataColumns.indexOf('oblast');
const raIx = dataColumns.indexOf('rayon');
const okIx = dataColumns.indexOf('okrug');
- filteredData = allData.filter(row => {
- const rowOb = obIx !== -1 ? String(row[obIx] || '').trim() : '';
- const rowRa = raIx !== -1 ? String(row[raIx] || '').trim() : '';
- const rowOk = okIx !== -1 ? String(row[okIx] || '').trim() : '';
- if (ob && rowOb !== ob) return false;
- if (ra && rowRa !== ra) return false;
- if (ok && rowOk !== ok) return false;
- return true;
- });
+ let data = allData;
+ if (ob || ra || ok) {
+ data = allData.filter(row => {
+ const rOb = obIx !== -1 ? String(row[obIx] || '').trim() : '';
+ const rRa = raIx !== -1 ? String(row[raIx] || '').trim() : '';
+ const rOk = okIx !== -1 ? String(row[okIx] || '').trim() : '';
+ if (ob && rOb !== ob) return false;
+ if (ra && rRa !== ra) return false;
+ if (ok && rOk !== ok) return false;
+ return true;
+ });
+ }
+ if (showMarkedOnly) {
+ data = data.filter((row, i) => markedIds.has(row._id));
+ }
+
+ filteredData = data;
renderTable();
}
function renderTable() {
- document.getElementById('countDisplay').textContent = filteredData.length;
-
+ const headers = allData.columns || [];
const head = document.getElementById('tableHead');
const body = document.getElementById('tableBody');
+ const total = document.getElementById('totalCount');
+ const markedSpan = document.getElementById('markedCount');
+
+ const markedCount = allData.filter(r => markedIds.has(r._id)).length;
+ markedSpan.textContent = markedCount;
if (filteredData.length === 0) {
- head.innerHTML = '';
- body.innerHTML = '
🔍 Нет данных по выбранным фильтрам
';
+ head.innerHTML = '
' + headers.map(h => `${h} `).join('') + '';
+ body.innerHTML = '
🔍 Нет данных по выбранным фильтрам
';
+ total.textContent = '0';
+ document.getElementById('markAllBtn').textContent = '✅ Отметить все';
return;
}
- const headers = allData.columns || Object.keys(allData[0] || {});
- head.innerHTML = '
' + headers.map(h => `${h} `).join('') + ' ';
- body.innerHTML = filteredData.map(row => {
- const vals = Array.isArray(row) ? row : headers.map(h => row[h] ?? '');
- return '
' + vals.map(v => `${v != null ? v : ''} `).join('') + ' ';
- }).join('');
+ total.textContent = filteredData.length;
+
+ // Group by district
+ const raIx = dataColumns.indexOf('rayon');
+ const okIx = dataColumns.indexOf('okrug');
+ const groups = {};
+ filteredData.forEach(row => {
+ const ra = raIx !== -1 ? String(row[raIx] || '').trim() : '';
+ const ok = okIx !== -1 ? String(row[okIx] || '').trim() : '';
+ const key = ra + ' → ' + ok;
+ if (!groups[key]) groups[key] = [];
+ groups[key].push(row);
+ });
+
+ let allMarkedInView = true;
+ let allUnmarkedInView = true;
+ filteredData.forEach(r => {
+ if (markedIds.has(r._id)) allUnmarkedInView = false;
+ else allMarkedInView = false;
+ });
+
+ const markAllBtn = document.getElementById('markAllBtn');
+ if (allMarkedInView) markAllBtn.textContent = '✕ Снять все в фильтре';
+ else markAllBtn.textContent = '✅ Отметить все в фильтре';
+
+ head.innerHTML = '
0 ? 'checked' : '') + '> ' + headers.map(h => `${h} `).join('') + '';
+
+ let html = '';
+ Object.entries(groups).forEach(([group, rows]) => {
+ const markedInGroup = rows.filter(r => markedIds.has(r._id)).length;
+ html += ``;
+ rows.forEach(row => {
+ const isMarked = markedIds.has(row._id);
+ html += `
+
+ ${headers.map(h => `${row[h] != null ? row[h] : ''} `).join('')}
+ `;
+ });
+ });
+
+ body.innerHTML = html;
+
+ // event listeners
+ document.getElementById('selectAll').onchange = function() {
+ filteredData.forEach(r => {
+ if (this.checked) markedIds.add(r._id);
+ else markedIds.delete(r._id);
+ });
+ renderTable();
+ };
+
+ document.querySelectorAll('.row-check').forEach(cb => {
+ cb.onchange = function() {
+ if (this.checked) markedIds.add(this.dataset.id);
+ else markedIds.delete(this.dataset.id);
+ renderTable();
+ };
+ });
+}
+
+function toggleGroup(groupName) {
+ const raIx = dataColumns.indexOf('rayon');
+ const okIx = dataColumns.indexOf('okrug');
+ const parts = groupName.split(' → ');
+ const ra = parts[0], ok = parts[1];
+ const rows = filteredData.filter(r => {
+ const rRa = raIx !== -1 ? String(r[raIx] || '').trim() : '';
+ const rOk = okIx !== -1 ? String(r[okIx] || '').trim() : '';
+ return rRa === ra && rOk === ok;
+ });
+ const allMarked = rows.every(r => markedIds.has(r._id));
+ rows.forEach(r => {
+ if (allMarked) markedIds.delete(r._id);
+ else markedIds.add(r._id);
+ });
+ renderTable();
}
function handleFile(file) {
@@ -250,55 +362,68 @@ function handleFile(file) {
const rows = json.slice(1).filter(r => r.some(c => c != null && c !== ''));
dataColumns = headers.map((h, i) => detectColumn(h) || ('col_' + i));
- allData = rows.map(r => {
+ allData = rows.map((r, idx) => {
const obj = {};
headers.forEach((h, i) => { obj[h] = r[i] != null ? r[i] : ''; });
- obj.columns = headers;
+ obj._id = rowId(obj, idx);
return obj;
});
allData.columns = headers;
+ // init marked from localStorage
+ markedIds = new Set();
+
const zone = document.getElementById('dropZone');
zone.classList.add('has-file');
- zone.innerHTML = `
✅ ${file.name} (${allData.length} записей)
`;
+ zone.innerHTML = `
✅
${file.name} (${allData.length} записей)
`;
initHierarchy(allData);
renderFilters();
applyFilter();
document.getElementById('resultArea').classList.remove('hidden');
} catch(err) {
- alert('Ошибка при чтении файла: ' + err.message);
+ alert('Ошибка: ' + err.message);
}
};
reader.readAsArrayBuffer(file);
}
-document.getElementById('fileInput').addEventListener('change', e => {
- if (e.target.files[0]) handleFile(e.target.files[0]);
-});
+document.getElementById('fileInput').onchange = e => { if (e.target.files[0]) handleFile(e.target.files[0]); };
+const dz = document.getElementById('dropZone');
+dz.onclick = () => document.getElementById('fileInput').click();
+dz.ondragover = e => { e.preventDefault(); dz.classList.add('dragover'); };
+dz.ondragleave = () => dz.classList.remove('dragover');
+dz.ondrop = e => { e.preventDefault(); dz.classList.remove('dragover'); if (e.dataTransfer.files[0]) handleFile(e.dataTransfer.files[0]); };
-const dropZone = document.getElementById('dropZone');
-dropZone.addEventListener('click', () => document.getElementById('fileInput').click());
-dropZone.addEventListener('dragover', e => { e.preventDefault(); dropZone.classList.add('dragover'); });
-dropZone.addEventListener('dragleave', () => dropZone.classList.remove('dragover'));
-dropZone.addEventListener('drop', e => {
- e.preventDefault();
- dropZone.classList.remove('dragover');
- if (e.dataTransfer.files[0]) handleFile(e.dataTransfer.files[0]);
-});
+document.getElementById('markAllBtn').onclick = () => {
+ const btn = document.getElementById('markAllBtn');
+ const allMarked = filteredData.length > 0 && filteredData.every(r => markedIds.has(r._id));
+ filteredData.forEach(r => {
+ if (allMarked) markedIds.delete(r._id);
+ else markedIds.add(r._id);
+ });
+ renderTable();
+};
-document.getElementById('exportBtn').addEventListener('click', () => {
- if (filteredData.length === 0) { alert('Нет данных для экспорта'); return; }
- const headers = allData.columns;
+document.getElementById('unmarkAllBtn').onclick = () => {
+ allData.forEach(r => markedIds.delete(r._id));
+ renderTable();
+};
+
+document.getElementById('exportBtn').onclick = () => {
+ const marked = allData.filter(r => markedIds.has(r._id));
+ if (marked.length === 0) { alert('Нет отмеченных населённых пунктов. Отметьте хотя бы один.'); return; }
+
+ const headers = ['Учитывается в расчётах', ...allData.columns];
const wsData = [headers];
- filteredData.forEach(row => {
- wsData.push(headers.map(h => row[h] != null ? row[h] : ''));
+ allData.forEach(row => {
+ wsData.push([markedIds.has(row._id) ? 'Да' : 'Нет', ...allData.columns.map(h => row[h] != null ? row[h] : '')]);
});
const ws = XLSX.utils.aoa_to_sheet(wsData);
const wb = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(wb, ws, 'СНП');
- XLSX.writeFile(wb, 'snp-vyborka.xlsx');
-});
+ XLSX.writeFile(wb, 'snp-otbor.xlsx');
+};