Форма ввода по 15 колонкам из Google Sheets + экспорт/импорт CSV

This commit is contained in:
Dauren777 2026-06-05 08:28:42 +00:00
parent 2477e26c30
commit d2ea436d89

View File

@ -1147,35 +1147,34 @@ body {
<div class="toggle-panel active" id="panel-input">
<div class="form-grid">
<div class="form-group">
<label>Дата проверки</label>
<label></label>
<input type="number" id="fNum" placeholder="Авто">
</div>
<div class="form-group">
<label>Дата</label>
<input type="date" id="fDate" required>
</div>
<div class="form-group">
<label>№ указания</label>
<input type="text" id="fDirective" placeholder="Номер указания">
</div>
<div class="form-group">
<label>Филиал</label>
<select id="fFilial">
<option value="">Выберите...</option>
<option>ОДС</option>
<option>ДРБ</option>
<option>ДИТ</option>
<option>Сервисная фабрика</option>
<option>ДКБ</option>
<option>ДУП</option>
<option>ДТК</option>
<option>СФ</option>
<option>ЦТО СФ</option>
<option>ЦЭиК</option>
<option>ОДС</option><option>ДРБ</option><option>ДИТ</option>
<option>Сервисная фабрика</option><option>ДКБ</option>
<option>ДУП</option><option>ДТК</option><option>СФ</option>
<option>ЦТО СФ</option><option>ЦЭиК</option>
</select>
</div>
<div class="form-group">
<label>Область</label>
<select id="fRegion">
<option value="">Выберите...</option>
<option>Акмолинская</option>
<option>Астана</option>
<option>Карагандинская</option>
<option>Улытауская</option>
<option>Костанайская</option>
<option>Павлодарская</option>
<option>Акмолинская</option><option>Астана</option>
<option>Карагандинская</option><option>Улытауская</option>
<option>Костанайская</option><option>Павлодарская</option>
<option>СКО</option>
</select>
</div>
@ -1187,10 +1186,6 @@ body {
<label>Объект с адресом</label>
<input type="text" id="fAddr" placeholder="Например: ул. Казахстанская 100а">
</div>
<div class="form-group">
<label>Кому выдано</label>
<input type="text" id="fIssuedTo" placeholder="Например: Начальник ЛТЦ">
</div>
<div class="form-group">
<label>Категория нарушения</label>
<select id="fCat">
@ -1204,27 +1199,38 @@ body {
<option>Санитарно-бытовые условия</option>
<option>организационные требования БиОТ</option>
<option>Производственная санитария</option>
<option>Инструкция по проведению 4-х ступенчатого контроля</option>
<option>Наряды-допуски</option>
<option>Инструкция по проведению 4-х ступенчатого контроля</option>
<option>Не обеспечение СИЗ</option>
<option>Политика в области ТСС</option>
<option>Требовании по организации в управлении транспортных средств</option>
</select>
</div>
<div class="form-group full">
<label>Категория нарушения (описание)</label>
<textarea id="fDesc" placeholder="Подробное описание выявленного нарушения..."></textarea>
</div>
<div class="form-group full">
<label>Ссылка на законодательство</label>
<textarea id="fLaw" rows="2" placeholder="Например: пп.4, п.2 статьи 182 Трудового кодекса РК..."></textarea>
</div>
<div class="form-group">
<label>Статус</label>
<label>Срок исполнения</label>
<input type="text" id="fDeadline" placeholder="Например: 14.01.2026г.">
</div>
<div class="form-group">
<label>Исполнено</label>
<select id="fStatus">
<option value="на контроле">На контроле</option>
<option value="исполнено">Исполнено</option>
</select>
</div>
<div class="form-group full">
<label>Описание нарушения</label>
<textarea id="fDesc" placeholder="Кратко опишите нарушение..."></textarea>
<label>Примечание</label>
<input type="text" id="fNote" placeholder="Примечание (необязательно)">
</div>
<div class="form-group">
<label>Срок исполнения</label>
<input type="date" id="fDeadline">
</div>
<div class="form-group">
<label>Проверяющий (кто выдал)</label>
<label>Кто выдал</label>
<select id="fInspector">
<option value="">Выберите...</option>
<option>Инженер по БиОТ Семидоцкий С.А.</option>
@ -1235,8 +1241,13 @@ body {
<option>Инженер ОБиОТ Садыков М.Ф.</option>
<option>Ведущий инженер ОБиОТ Тумабаева С.А.</option>
<option>Инженер по БиОТ Джусупова А.Т.</option>
<option>Ведущий инженер ОБиОТ Федоськин А.Н.</option>
</select>
</div>
<div class="form-group">
<label>Кому выдано</label>
<input type="text" id="fIssuedTo" placeholder="Например: Начальник ЛТЦ">
</div>
</div>
<div class="form-actions">
<button class="btn btn-blue" id="btnAdd">Добавить запись</button>
@ -1625,13 +1636,13 @@ body {
var fixed = isFixed(r.status);
html += '<div class="entry-card">' +
'<span class="entry-date">' + escHtml(r.date || '—') + '</span>' +
'<span class="entry-cat">' + escHtml(normalizeCategory(r.category || r.cat || '')) + '</span>' +
'<span class="entry-cat">' + escHtml(normalizeCategory(r.cat || r.category || '')) + '</span>' +
'<span class="entry-desc">' + escHtml((r.desc || r.description || '').slice(0, 80)) + '</span>' +
'<span class="entry-status ' + (fixed ? 'fixed' : 'pending') + '">' + (fixed ? 'Исполнено' : 'На контроле') + '</span>' +
'<button class="entry-del" data-id="' + r.id + '" title="Удалить">&times;</button>' +
'</div>';
});
if (data.length === 0) html = '<p style="color:var(--gray-500);text-align:center;padding:40px">Нет записей. Добавьте через форму «Ввод данных».</p>';
if (data.length === 0) html = '<p style="color:var(--gray-500);text-align:center;padding:40px">Нет записей. Добавьте через вкладку «Ввод данных».</p>';
if (data.length > 200) html += '<p style="font-size:13px;color:var(--gray-500);text-align:center">Показаны последние 200 из ' + data.length + '</p>';
document.getElementById('entriesList').innerHTML = html;
@ -1646,32 +1657,39 @@ body {
// ---- Form handling ----
function submitForm() {
var entry = {
num: document.getElementById('fNum').value,
date: document.getElementById('fDate').value,
directive: document.getElementById('fDirective').value,
filial: document.getElementById('fFilial').value,
region: document.getElementById('fRegion').value,
city: document.getElementById('fCity').value,
addr: document.getElementById('fAddr').value,
issuedTo: document.getElementById('fIssuedTo').value,
cat: document.getElementById('fCat').value,
status: document.getElementById('fStatus').value,
desc: document.getElementById('fDesc').value,
law: document.getElementById('fLaw').value,
deadline: document.getElementById('fDeadline').value,
inspector: document.getElementById('fInspector').value
status: document.getElementById('fStatus').value,
note: document.getElementById('fNote').value,
inspector: document.getElementById('fInspector').value,
issuedTo: document.getElementById('fIssuedTo').value
};
if (!entry.date || !entry.filial || !entry.cat || !entry.desc) {
showMsg('Заполните обязательные поля: дата, филиал, категория, описание', 'err');
showMsg('Заполните обязательные поля: Дата, Филиал, Категория, Описание', 'err');
return;
}
addEntry(entry);
showMsg('Запись добавлена!', 'ok');
document.getElementById('fDesc').value = '';
// Clear text fields, keep dropdowns
document.getElementById('fNum').value = '';
document.getElementById('fDate').value = '';
document.getElementById('fIssuedTo').value = '';
document.getElementById('fAddr').value = '';
document.getElementById('fCity').value = '';
document.getElementById('fDirective').value = '';
document.getElementById('fDesc').value = '';
document.getElementById('fLaw').value = '';
document.getElementById('fDeadline').value = '';
document.getElementById('fNote').value = '';
document.getElementById('fIssuedTo').value = '';
renderAll();
setTimeout(function() { showMsg('', ''); }, 2500);
}
@ -1686,13 +1704,14 @@ body {
function exportCSV() {
var data = loadData();
if (data.length === 0) { alert('Нет данных для экспорта.'); return; }
var header = 'Дата,Филиал,Область,Город/Район,Объект,Категория нарушения,Описание,Статус,Срок,Проверяющий,Кому выдано';
var header = '№,Дата,№ указания,Филиал,Область,Город/Район,Объект с адресом,Категория нарушения,Категория нарушения,Ссылка на законодательство,Срок исполнения,исполнено,Примечание,кто выдал,кому выдано';
var lines = [header];
data.forEach(function(r) {
lines.push([
r.date || '', r.filial || '', r.region || '', r.city || '',
r.addr || '', r.cat || r.category || '', r.desc || r.description || '',
r.status || '', r.deadline || '', r.inspector || r.issuedBy || '', r.issuedTo || ''
r.num || '', r.date || '', r.directive || '', r.filial || '', r.region || '',
r.city || '', r.addr || '', r.cat || r.category || '', r.desc || r.description || '',
r.law || '', r.deadline || '', r.status || '', r.note || '',
r.inspector || r.issuedBy || '', r.issuedTo || ''
].map(function(v) { return '"' + String(v).replace(/"/g, '""') + '"'; }).join(','));
});
var blob = new Blob(['\uFEFF' + lines.join('\n')], { type: 'text/csv;charset=utf-8' });
@ -1740,36 +1759,47 @@ body {
return -1;
}
var ciNum = idx(['№']);
var ciDate = idx(['дата']);
var ciDirective = idx(['указания','№ указания']);
var ciFilial = idx(['филиал']);
var ciRegion = idx(['область','регион']);
var ciCity = idx(['город','район']);
var ciCity = idx(['город','район','населен']);
var ciAddr = idx(['объект','адрес']);
var ciCat = idx(['категор','нарушен']);
// Second "Категория нарушения" = description
var ciDesc = -1;
for (var hi = 0; hi < headers.length; hi++) {
if (headers[hi].indexOf('категор') !== -1 && hi !== ciCat) { ciDesc = hi; break; }
if (headers[hi].indexOf('описан') !== -1 || headers[hi].indexOf('суть') !== -1) { ciDesc = hi; break; }
if (headers[hi].indexOf('описан') !== -1) { ciDesc = hi; break; }
}
if (ciDesc < 0) ciDesc = ciCat >= 0 ? ciCat + 1 : -1;
var ciStatus = idx(['исполнен','статус','устран']);
if (ciDesc < 0 && ciCat >= 0) ciDesc = ciCat + 1;
var ciLaw = idx(['законодательств','ссылка','основание']);
var ciDeadline = idx(['срок']);
var ciInspector = idx(['выдал','кто выдал','проверяющ']);
var ciStatus = idx(['исполнен','статус','устран']);
var ciNote = idx(['примечан']);
var ciInspector = idx(['выдал','кто выдал']);
var ciIssued = idx(['кому','выдано']);
var entries = [];
data.forEach(function(r) {
if (r.length < 2) return;
entries.push({
num: ciNum >= 0 ? r[ciNum] || '' : '',
date: ciDate >= 0 ? r[ciDate] || '' : '',
directive: ciDirective >= 0 ? r[ciDirective] || '' : '',
filial: ciFilial >= 0 ? r[ciFilial] || '' : '',
region: ciRegion >= 0 ? r[ciRegion] || '' : '',
city: ciCity >= 0 ? r[ciCity] || '' : '',
addr: ciAddr >= 0 ? r[ciAddr] || '' : '',
cat: ciCat >= 0 ? r[ciCat] || '' : '',
desc: ciDesc >= 0 && ciDesc < r.length ? r[ciDesc] || '' : '',
status: ciStatus >= 0 ? r[ciStatus] || '' : '',
law: ciLaw >= 0 ? r[ciLaw] || '' : '',
deadline: ciDeadline >= 0 ? r[ciDeadline] || '' : '',
status: ciStatus >= 0 ? r[ciStatus] || '' : '',
note: ciNote >= 0 ? r[ciNote] || '' : '',
inspector: ciInspector >= 0 ? r[ciInspector] || '' : '',
issuedTo: ciIssued >= 0 ? r[ciIssued] || '' : ''
});
@ -1804,21 +1834,40 @@ body {
}
function generateSampleCSV() {
var header = 'Дата,Филиал,Область,Город/Район,Объект с адресом,Категория нарушения,Описание нарушения,Срок исполнения,исполнено,кто выдал,кому выдано';
var header = '№,Дата,№ указания,Филиал,Область,Город/Район,Объект с адресом,Категория нарушения,Категория нарушения,Ссылка на законодательство,Срок исполнения,исполнено,Примечание,кто выдал,кому выдано';
var filials = ['ОДС','ДРБ','ДИТ','Сервисная фабрика','ДКБ','ДУП','ЦТО СФ','ЦЭиК'];
var oblasts = ['Акмолинская','Карагандинская','Астана','Астана','Улытауская','Карагандинская','Акмолинская'];
var oblasts = ['Акмолинская','Карагандинская','Астана','Улытауская'];
var cities = ['Шахтинск','Астана','Караганда','Темиртау','Щучинск','Атбасар','Балхаш','Кокшетау'];
var inspectors = [
'Инженер по БиОТ Семидоцкий С.А.','Ведущий инженер ОБиОТ Туржанов А.Т.',
'Инженер ОБиОТ Бачинская Н.В.','Ведущий инженер ОБиОТ Ажакметов М.З.',
'Ведущий инженер ОБиОТ Баяхметова Ж.Т.','Инженер ОБиОТ Садыков М.Ф.'
];
var realCats = ['основные док-ты по БиОТ','Пожарная безопасность','Электробезопасность','СИЗ','Транспортная безопасность','Промышленная безопасность','Санитарно-бытовые условия','организационные требования БиОТ'];
var cats = ['основные док-ты по БиОТ','Пожарная безопасность','Электробезопасность','СИЗ','Транспортная безопасность','Промышленная безопасность','Санитарно-бытовые условия','организационные требования БиОТ'];
var descs = [
'Отсутствует журнал инструктажа','Не проведён повторный инструктаж','Работники не ознакомлены с регламентом СИЗ',
'Просроченные диэлектрические перчатки','Неактуальные инструкции по ТБ','Отсутствует аптечка',
'Пожарный кран не проверялся','Работники без касок','Прошёл срок поверки инструмента',
'Аварийный выход заблокирован','На территории скопление снега'
'Отсутствует журнал инструктажа на рабочем месте',
'Не проведён повторный инструктаж за 1 квартал 2026',
'Работники не ознакомлены с регламентом обеспечения СИЗ',
'Форма журнала наряд-допусков не соответствует правилам',
'Просроченные диэлектрические перчатки',
'Неактуальные инструкции по ТБ по видам работ',
'Отсутствует аптечка для оказания первой помощи',
'Пожарный кран не проверялся на работоспособность',
'Работники не применяли СИЗ (без касок, пояса)',
'Прошёл срок поверки инструмента',
'Аварийный выход заблокирован',
'На территории скопление снега, требуется вывоз'
];
var laws = [
'пп.4, п.2 статьи 182 Трудового кодекса РК',
'Приказ №55 МЧС РК от 21.02.2022',
'Приказ Министра энергетики РК от 19.03.2015 №222',
'Распоряжение №253 от 31.10.2025',
'Распоряжение №271 от 19.11.2025',
'Приказ №262 от 14.11.2018'
];
var inspectors = [
'Инженер по БиОТ Семидоцкий С.А.',
'Ведущий инженер ОБиОТ Туржанов А.Т.',
'Инженер ОБиОТ Бачинская Н.В.',
'Ведущий инженер ОБиОТ Ажакметов М.З.',
'Ведущий инженер ОБиОТ Баяхметова Ж.Т.',
'Инженер ОБиОТ Садыков М.Ф.'
];
var statuses = ['исполнено','исполнено','исполнено','на контроле','на контроле','исполнено','на контроле'];
var months = ['01','02','03','04','05','06'];
@ -1826,11 +1875,18 @@ body {
var lines = [header];
for (var i = 0; i < 200; i++) {
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(','));
lines.push([
i+1, d, Math.floor(Math.random()*20)+1,
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),
cats[Math.floor(Math.random()*cats.length)],
descs[Math.floor(Math.random()*descs.length)],
laws[Math.floor(Math.random()*laws.length)],
d, statuses[Math.floor(Math.random()*statuses.length)],
'', inspectors[Math.floor(Math.random()*inspectors.length)], ''
].join(','));
}
return lines.join('\n');
}