Добавлена загрузка фото нарушения (base64 в localStorage, до 5 МБ)
This commit is contained in:
parent
d2ea436d89
commit
cec7f042d9
172
index.html
172
index.html
@ -962,6 +962,94 @@ body {
|
||||
background: var(--gray-50);
|
||||
}
|
||||
|
||||
/* Photo upload */
|
||||
.photo-upload {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.photo-upload input[type="file"] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.photo-label {
|
||||
display: inline-block;
|
||||
padding: 8px 18px;
|
||||
background: var(--gray-100);
|
||||
border: 1px solid var(--gray-200);
|
||||
border-radius: 8px;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
color: var(--ink);
|
||||
transition: border-color 0.15s;
|
||||
}
|
||||
|
||||
.photo-label:hover {
|
||||
border-color: var(--blue);
|
||||
background: var(--blue-50);
|
||||
}
|
||||
|
||||
.photo-name {
|
||||
font-size: 13px;
|
||||
color: var(--gray-500);
|
||||
max-width: 200px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.photo-clear {
|
||||
background: none;
|
||||
border: none;
|
||||
font-size: 20px;
|
||||
color: var(--red);
|
||||
cursor: pointer;
|
||||
line-height: 1;
|
||||
padding: 0 4px;
|
||||
}
|
||||
|
||||
.photo-preview img {
|
||||
max-width: 200px;
|
||||
max-height: 150px;
|
||||
border-radius: 8px;
|
||||
border: 1px solid var(--gray-200);
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.entry-photo {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
border-radius: 6px;
|
||||
object-fit: cover;
|
||||
border: 1px solid var(--gray-200);
|
||||
flex-shrink: 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.photo-viewer {
|
||||
display: none;
|
||||
position: fixed;
|
||||
top: 0; left: 0; right: 0; bottom: 0;
|
||||
background: rgba(0,0,0,0.85);
|
||||
z-index: 9999;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.photo-viewer.active {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.photo-viewer img {
|
||||
max-width: 90vw;
|
||||
max-height: 90vh;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
/* Mobile */
|
||||
@media (max-width: 640px) {
|
||||
.hero { padding: 64px 0 48px; }
|
||||
@ -1210,6 +1298,16 @@ body {
|
||||
<label>Категория нарушения (описание)</label>
|
||||
<textarea id="fDesc" placeholder="Подробное описание выявленного нарушения..."></textarea>
|
||||
</div>
|
||||
<div class="form-group full">
|
||||
<label>Фото нарушения</label>
|
||||
<div class="photo-upload">
|
||||
<input type="file" id="fPhoto" accept="image/*" capture="environment">
|
||||
<label for="fPhoto" class="photo-label">Выбрать фото</label>
|
||||
<span class="photo-name" id="photoName"></span>
|
||||
<button type="button" class="photo-clear" id="photoClear" style="display:none">×</button>
|
||||
</div>
|
||||
<div class="photo-preview" id="photoPreview"></div>
|
||||
</div>
|
||||
<div class="form-group full">
|
||||
<label>Ссылка на законодательство</label>
|
||||
<textarea id="fLaw" rows="2" placeholder="Например: пп.4, п.2 статьи 182 Трудового кодекса РК..."></textarea>
|
||||
@ -1634,7 +1732,12 @@ body {
|
||||
var html = '';
|
||||
data.slice(0, 200).forEach(function(r, i) {
|
||||
var fixed = isFixed(r.status);
|
||||
var photoHtml = '';
|
||||
if (r.photo) {
|
||||
photoHtml = '<img class="entry-photo" src="' + r.photo + '" data-photo="' + r.id + '" alt="фото">';
|
||||
}
|
||||
html += '<div class="entry-card">' +
|
||||
photoHtml +
|
||||
'<span class="entry-date">' + escHtml(r.date || '—') + '</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>' +
|
||||
@ -1652,9 +1755,21 @@ body {
|
||||
renderAll();
|
||||
});
|
||||
});
|
||||
|
||||
// Photo click → viewer
|
||||
document.querySelectorAll('.entry-photo').forEach(function(img) {
|
||||
img.addEventListener('click', function(e) {
|
||||
e.stopPropagation();
|
||||
var viewer = document.getElementById('photoViewer');
|
||||
document.getElementById('photoViewerImg').src = img.src;
|
||||
viewer.classList.add('active');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// ---- Form handling ----
|
||||
var photoData = null;
|
||||
|
||||
function submitForm() {
|
||||
var entry = {
|
||||
num: document.getElementById('fNum').value,
|
||||
@ -1671,7 +1786,8 @@ body {
|
||||
status: document.getElementById('fStatus').value,
|
||||
note: document.getElementById('fNote').value,
|
||||
inspector: document.getElementById('fInspector').value,
|
||||
issuedTo: document.getElementById('fIssuedTo').value
|
||||
issuedTo: document.getElementById('fIssuedTo').value,
|
||||
photo: photoData
|
||||
};
|
||||
|
||||
if (!entry.date || !entry.filial || !entry.cat || !entry.desc) {
|
||||
@ -1679,6 +1795,29 @@ body {
|
||||
return;
|
||||
}
|
||||
|
||||
addEntry(entry);
|
||||
showMsg('Запись добавлена!', 'ok');
|
||||
document.getElementById('fNum').value = '';
|
||||
document.getElementById('fDate').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 = '';
|
||||
clearPhoto();
|
||||
renderAll();
|
||||
setTimeout(function() { showMsg('', ''); }, 2500);
|
||||
}
|
||||
|
||||
function clearPhoto() {
|
||||
photoData = null;
|
||||
document.getElementById('fPhoto').value = '';
|
||||
document.getElementById('photoName').textContent = '';
|
||||
document.getElementById('photoClear').style.display = 'none';
|
||||
document.getElementById('photoPreview').innerHTML = '';
|
||||
}
|
||||
|
||||
addEntry(entry);
|
||||
showMsg('Запись добавлена!', 'ok');
|
||||
// Clear text fields, keep dropdowns
|
||||
@ -1926,6 +2065,32 @@ body {
|
||||
// Form submit
|
||||
document.getElementById('btnAdd').addEventListener('click', submitForm);
|
||||
|
||||
// Photo file input
|
||||
document.getElementById('fPhoto').addEventListener('change', function() {
|
||||
var file = this.files[0];
|
||||
if (!file) return;
|
||||
if (file.size > 5 * 1024 * 1024) {
|
||||
showMsg('Фото больше 5 МБ — слишком большое для хранения в браузере', 'err');
|
||||
this.value = '';
|
||||
return;
|
||||
}
|
||||
document.getElementById('photoName').textContent = file.name;
|
||||
document.getElementById('photoClear').style.display = 'inline';
|
||||
var reader = new FileReader();
|
||||
reader.onload = function(e) {
|
||||
photoData = e.target.result;
|
||||
document.getElementById('photoPreview').innerHTML = '<img src="' + photoData + '">';
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
});
|
||||
|
||||
document.getElementById('photoClear').addEventListener('click', clearPhoto);
|
||||
|
||||
// Photo viewer close
|
||||
document.getElementById('photoViewer').addEventListener('click', function() {
|
||||
this.classList.remove('active');
|
||||
});
|
||||
|
||||
// Period filter
|
||||
document.getElementById('perPreset').addEventListener('change', function() {
|
||||
document.getElementById('perCustom').style.display = this.value === 'custom' ? 'inline' : 'none';
|
||||
@ -1967,5 +2132,10 @@ body {
|
||||
})();
|
||||
</script>
|
||||
|
||||
<!-- Photo viewer overlay -->
|
||||
<div class="photo-viewer" id="photoViewer">
|
||||
<img id="photoViewerImg" src="" alt="Фото нарушения">
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user