';
-
- if (data.totalPending > data.totalFixed) {
- html += '
Рекомендации
На контроле ' + data.totalPending +
- ' нарушений — требуется усилить контроль устранения. ';
- if (topCat) {
- var cat = topCat[0];
- if (cat === 'Средства индивидуальной защиты') html += 'По СИЗ: провести внеплановые проверки применения средств защиты и целевой инструктаж. ';
- else if (cat === 'Наряды-допуски') html += 'По нарядам-допускам: организовать дополнительное обучение и выборочный аудит. ';
- else if (cat === 'Электробезопасность') html += 'По электробезопасности: усилить контроль со стороны ответственных лиц. ';
- else if (cat === 'Пожарная безопасность') html += 'По пожарной безопасности: проверить сроки и качество инструктажей. ';
- else html += 'По «' + escHtml(cat) + '»: провести внеплановую проверку и целевой инструктаж. ';
- }
- html += 'Рекомендуется еженедельный мониторинг.
';
- }
-
- document.getElementById('conclusions').innerHTML = html;
- }
-
- function processFile(file) {
+ function processCSVFile(file) {
document.getElementById('uploadStatus').textContent = 'Обработка...';
var reader = new FileReader();
reader.onload = function(e) {
try {
var text = e.target.result;
- // Remove BOM
if (text.charCodeAt(0) === 0xFEFF) text = text.slice(1);
-
- // Auto-detect delimiter
- var commaCount = (text.split('\n')[0] || '').split(',').length;
- var semiCount = (text.split('\n')[0] || '').split(';').length;
- if (semiCount > commaCount + 2) {
- text = text.replace(/;/g, ',');
- }
-
var rows = parseCSV(text);
- if (rows.length < 2) {
- document.getElementById('uploadStatus').textContent = 'Ошибка: файл пуст.';
- return;
+ var count = importCSV(rows);
+ if (count === 0) {
+ document.getElementById('uploadStatus').textContent = 'Не удалось распознать данные.';
+ } else {
+ document.getElementById('uploadStatus').textContent = 'Импортировано: ' + count + ' записей из «' + file.name + '»';
+ renderAll();
}
- var data = analyzeData(rows);
- if (!data || data.totalRecords === 0) {
- document.getElementById('uploadStatus').textContent = 'Ошибка: не удалось распознать данные.';
- return;
- }
- document.getElementById('uploadStatus').textContent = 'Загружен «' + file.name + '» (' + data.totalRecords + ' записей)';
- renderResults(data);
- } catch (err) {
+ } catch(err) {
document.getElementById('uploadStatus').textContent = 'Ошибка: ' + err.message;
}
};
reader.readAsText(file, 'UTF-8');
}
- var dropArea = document.getElementById('dropArea');
- var fileInput = document.getElementById('fileInput');
-
- dropArea.addEventListener('click', function() { fileInput.click(); });
- fileInput.addEventListener('change', function() {
- if (fileInput.files.length > 0) processFile(fileInput.files[0]);
- });
-
- dropArea.addEventListener('dragover', function(e) {
- e.preventDefault();
- dropArea.classList.add('drag-over');
- });
- dropArea.addEventListener('dragleave', function() {
- dropArea.classList.remove('drag-over');
- });
- dropArea.addEventListener('drop', function(e) {
- e.preventDefault();
- dropArea.classList.remove('drag-over');
- if (e.dataTransfer.files.length > 0) processFile(e.dataTransfer.files[0]);
- });
-
- document.querySelectorAll('.tab-btn').forEach(function(btn) {
- btn.addEventListener('click', function() {
- document.querySelectorAll('.tab-btn').forEach(function(b) { b.classList.remove('active'); });
- document.querySelectorAll('.tab-content').forEach(function(c) { c.classList.remove('active'); });
- btn.classList.add('active');
- var target = document.getElementById(btn.getAttribute('data-tab'));
- if (target) target.classList.add('active');
- });
- });
-
- document.getElementById('sampleBtn').addEventListener('click', function() {
- document.getElementById('uploadStatus').textContent = 'Загрузка демо-данных...';
- var sampleCSV = generateSampleCSV();
- var blob = new Blob(['\uFEFF' + sampleCSV], { type: 'text/csv;charset=utf-8' });
- processFile(new File([blob], 'demo_data.csv', { type: 'text/csv' }));
- });
-
function generateSampleCSV() {
var header = 'Дата,Филиал,Область,Город/Район,Объект с адресом,Категория нарушения,Описание нарушения,Срок исполнения,исполнено,кто выдал,кому выдано';
- var filials = ['ОДС','ОДС','ОДС','ДРБ','ДИТ','Сервисная фабрика','Сервисная фабрика','ДКБ','ДУП','СФ','ЦТО СФ','ЦЭиК'];
- var oblasts = ['Акмолинская','Карагандинская','Астана','Астана','Улытауская','Карагандинская','Акмолинская','Астана','Карагандинская'];
+ var filials = ['ОДС','ДРБ','ДИТ','Сервисная фабрика','ДКБ','ДУП','ЦТО СФ','ЦЭиК'];
+ var oblasts = ['Акмолинская','Карагандинская','Астана','Астана','Улытауская','Карагандинская','Акмолинская'];
var cities = ['Шахтинск','Астана','Караганда','Темиртау','Щучинск','Атбасар','Балхаш','Кокшетау'];
var inspectors = [
- 'Инженер по БиОТ Семидоцкий С.А.',
- 'Ведущий инженер ОБиОТ Туржанов А.Т.',
- 'Инженер ОБиОТ Бачинская Н.В.',
- 'Ведущий инженер ОБиОТ Ажакметов М.З.',
- 'Ведущий инженер ОБиОТ Баяхметова Ж.Т.',
- 'Инженер ОБиОТ Садыков М.Ф.',
- 'Ведущий инженер ОБиОТ Тумабаева С.А.',
- 'Инженер по БиОТ Джусупова А.Т.',
- 'Инженер по БиОТ Кришталь В.П.'
- ];
- var realCats = [
- 'основные док-ты по БиОТ','основные док-ты по БиОТ','основные документы по БиОТ',
- 'Пожарная безопасность','Пожарная безопасность','пожарная безопасность',
- 'Электробезопасность',
- 'СИЗ','СИЗ','Не обеспечение СИЗ',
- 'Транспортная безопасность',
- 'Промышленная безопасность','промышленная безопасность',
- 'Санитарно-бытовые условия',
- 'организационные требования БиОТ','Инструкция по проведению 4-х ступенчатого контроля',
- 'Производственная санитария'
+ 'Инженер по БиОТ Семидоцкий С.А.','Ведущий инженер ОБиОТ Туржанов А.Т.',
+ 'Инженер ОБиОТ Бачинская Н.В.','Ведущий инженер ОБиОТ Ажакметов М.З.',
+ 'Ведущий инженер ОБиОТ Баяхметова Ж.Т.','Инженер ОБиОТ Садыков М.Ф.'
];
+ var realCats = ['основные док-ты по БиОТ','Пожарная безопасность','Электробезопасность','СИЗ','Транспортная безопасность','Промышленная безопасность','Санитарно-бытовые условия','организационные требования БиОТ'];
var descs = [
- 'Отсутствует журнал инструктажа на рабочем месте',
- 'Не проведён повторный инструктаж за 1 квартал',
- 'Работники не ознакомлены с регламентом обеспечения СИЗ',
- 'Форма журнала наряд-допусков не соответствует правилам',
- 'Просроченные диэлектрические перчатки',
- 'Лестница не имеет даты проверки лабораторных испытаний',
- 'Неактуальные инструкции по ТБ по видам работ',
- 'Отсутствует аптечка для оказания первой помощи',
- 'Пожарный кран не проверялся на работоспособность',
- 'Работники не применяли СИЗ (без касок, пояса)',
- 'Прошёл срок поверки инструмента с изолированными ручками',
- 'Не корректно ведётся журнал 4-х ступенчатого контроля',
- 'На территории скопление снега, требуется вывоз',
- 'Отсутствует комната для сушки спецодежды',
- 'Аварийный выход заблокирован',
- 'В журнале учёта такелажных средств нет подписи председателя',
- 'Нет таблички об ответственности по пожарной безопасности',
- 'Работники не обеспечены спецодеждой и обувью'
+ 'Отсутствует журнал инструктажа','Не проведён повторный инструктаж','Работники не ознакомлены с регламентом СИЗ',
+ 'Просроченные диэлектрические перчатки','Неактуальные инструкции по ТБ','Отсутствует аптечка',
+ 'Пожарный кран не проверялся','Работники без касок','Прошёл срок поверки инструмента',
+ 'Аварийный выход заблокирован','На территории скопление снега'
];
var statuses = ['исполнено','исполнено','исполнено','на контроле','на контроле','исполнено','на контроле'];
- var months = ['01','01','02','02','03','03','04','04','05','05','06'];
+ var months = ['01','02','03','04','05','06'];
var lines = [header];
for (var i = 0; i < 200; i++) {
- var m = months[Math.floor(Math.random() * months.length)];
- var day = String(Math.floor(Math.random() * 28) + 1).padStart(2, '0');
- var date = day + '.' + m + '.2026';
- var fil = filials[Math.floor(Math.random() * filials.length)];
- var obl = oblasts[Math.floor(Math.random() * oblasts.length)];
- var city = cities[Math.floor(Math.random() * cities.length)];
- var addr = 'ул. Примерная ' + (Math.floor(Math.random() * 50) + 1);
- var cat = realCats[Math.floor(Math.random() * realCats.length)];
- var desc = descs[Math.floor(Math.random() * descs.length)];
- var insp = inspectors[Math.floor(Math.random() * inspectors.length)];
- var status = statuses[Math.floor(Math.random() * statuses.length)];
-
- lines.push([date, fil, obl, city, addr, cat, desc, '', status, insp, ''].join(','));
+ var d = String(Math.floor(Math.random()*28)+1).padStart(2,'0') + '.' + months[Math.floor(Math.random()*months.length)] + '.2026';
+ lines.push([d, filials[Math.floor(Math.random()*filials.length)], oblasts[Math.floor(Math.random()*oblasts.length)],
+ cities[Math.floor(Math.random()*cities.length)], 'ул. Примерная '+(Math.floor(Math.random()*50)+1),
+ realCats[Math.floor(Math.random()*realCats.length)], descs[Math.floor(Math.random()*descs.length)],
+ '', statuses[Math.floor(Math.random()*statuses.length)],
+ inspectors[Math.floor(Math.random()*inspectors.length)], ''].join(','));
}
return lines.join('\n');
}
+ // ---- Panel switching ----
+ function switchPanel(name) {
+ document.querySelectorAll('.toggle-panel').forEach(function(p) { p.classList.remove('active'); });
+ document.querySelectorAll('.panel-switch button').forEach(function(b) { b.classList.remove('active'); });
+ var panel = document.getElementById(name);
+ if (panel) panel.classList.add('active');
+ var btn = document.querySelector('[data-panel="' + name + '"]');
+ if (btn) btn.classList.add('active');
+
+ if (name === 'panel-dashboard') renderDashboard();
+ if (name === 'panel-list') renderEntryList();
+ }
+
+ function renderAll() {
+ renderDashboard();
+ renderEntryList();
+ }
+
+ // ---- ESC helper ----
+ function escHtml(s) {
+ return String(s).replace(/&/g,'&').replace(//g,'>').replace(/"/g,'"');
+ }
+
+ // ---- Init ----
+ function init() {
+ // Panel switch clicks
+ document.querySelectorAll('.panel-switch button').forEach(function(btn) {
+ btn.addEventListener('click', function() {
+ switchPanel(btn.getAttribute('data-panel'));
+ });
+ });
+
+ // Form submit
+ document.getElementById('btnAdd').addEventListener('click', submitForm);
+
+ // Period filter
+ document.getElementById('perPreset').addEventListener('change', function() {
+ document.getElementById('perCustom').style.display = this.value === 'custom' ? 'inline' : 'none';
+ renderDashboard();
+ });
+ document.getElementById('btnPerApply').addEventListener('click', renderDashboard);
+
+ // Export / Clear
+ document.getElementById('btnExportCSV').addEventListener('click', exportCSV);
+ document.getElementById('btnClear').addEventListener('click', clearAll);
+
+ // File drop / import
+ var dropArea = document.getElementById('dropArea');
+ var fileInput = document.getElementById('fileInput');
+ dropArea.addEventListener('click', function() { fileInput.click(); });
+ fileInput.addEventListener('change', function() {
+ if (fileInput.files.length > 0) processCSVFile(fileInput.files[0]);
+ });
+ dropArea.addEventListener('dragover', function(e) { e.preventDefault(); dropArea.classList.add('drag-over'); });
+ dropArea.addEventListener('dragleave', function() { dropArea.classList.remove('drag-over'); });
+ dropArea.addEventListener('drop', function(e) {
+ e.preventDefault(); dropArea.classList.remove('drag-over');
+ if (e.dataTransfer.files.length > 0) processCSVFile(e.dataTransfer.files[0]);
+ });
+
+ // Sample data
+ document.getElementById('sampleBtn').addEventListener('click', function() {
+ document.getElementById('uploadStatus').textContent = 'Загрузка демо-данных...';
+ var blob = new Blob(['\uFEFF' + generateSampleCSV()], { type: 'text/csv;charset=utf-8' });
+ processCSVFile(new File([blob], 'demo.csv', { type: 'text/csv' }));
+ });
+
+ // Initial render
+ renderDashboard();
+ renderEntryList();
+ }
+
+ init();
})();