Добавлена загрузка фото нарушения (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);
|
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 */
|
/* Mobile */
|
||||||
@media (max-width: 640px) {
|
@media (max-width: 640px) {
|
||||||
.hero { padding: 64px 0 48px; }
|
.hero { padding: 64px 0 48px; }
|
||||||
@ -1210,6 +1298,16 @@ body {
|
|||||||
<label>Категория нарушения (описание)</label>
|
<label>Категория нарушения (описание)</label>
|
||||||
<textarea id="fDesc" placeholder="Подробное описание выявленного нарушения..."></textarea>
|
<textarea id="fDesc" placeholder="Подробное описание выявленного нарушения..."></textarea>
|
||||||
</div>
|
</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">
|
<div class="form-group full">
|
||||||
<label>Ссылка на законодательство</label>
|
<label>Ссылка на законодательство</label>
|
||||||
<textarea id="fLaw" rows="2" placeholder="Например: пп.4, п.2 статьи 182 Трудового кодекса РК..."></textarea>
|
<textarea id="fLaw" rows="2" placeholder="Например: пп.4, п.2 статьи 182 Трудового кодекса РК..."></textarea>
|
||||||
@ -1634,7 +1732,12 @@ body {
|
|||||||
var html = '';
|
var html = '';
|
||||||
data.slice(0, 200).forEach(function(r, i) {
|
data.slice(0, 200).forEach(function(r, i) {
|
||||||
var fixed = isFixed(r.status);
|
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">' +
|
html += '<div class="entry-card">' +
|
||||||
|
photoHtml +
|
||||||
'<span class="entry-date">' + escHtml(r.date || '—') + '</span>' +
|
'<span class="entry-date">' + escHtml(r.date || '—') + '</span>' +
|
||||||
'<span class="entry-cat">' + escHtml(normalizeCategory(r.cat || r.category || '')) + '</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-desc">' + escHtml((r.desc || r.description || '').slice(0, 80)) + '</span>' +
|
||||||
@ -1652,9 +1755,21 @@ body {
|
|||||||
renderAll();
|
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 ----
|
// ---- Form handling ----
|
||||||
|
var photoData = null;
|
||||||
|
|
||||||
function submitForm() {
|
function submitForm() {
|
||||||
var entry = {
|
var entry = {
|
||||||
num: document.getElementById('fNum').value,
|
num: document.getElementById('fNum').value,
|
||||||
@ -1671,7 +1786,8 @@ body {
|
|||||||
status: document.getElementById('fStatus').value,
|
status: document.getElementById('fStatus').value,
|
||||||
note: document.getElementById('fNote').value,
|
note: document.getElementById('fNote').value,
|
||||||
inspector: document.getElementById('fInspector').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) {
|
if (!entry.date || !entry.filial || !entry.cat || !entry.desc) {
|
||||||
@ -1679,6 +1795,29 @@ body {
|
|||||||
return;
|
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);
|
addEntry(entry);
|
||||||
showMsg('Запись добавлена!', 'ok');
|
showMsg('Запись добавлена!', 'ok');
|
||||||
// Clear text fields, keep dropdowns
|
// Clear text fields, keep dropdowns
|
||||||
@ -1926,6 +2065,32 @@ body {
|
|||||||
// Form submit
|
// Form submit
|
||||||
document.getElementById('btnAdd').addEventListener('click', submitForm);
|
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
|
// Period filter
|
||||||
document.getElementById('perPreset').addEventListener('change', function() {
|
document.getElementById('perPreset').addEventListener('change', function() {
|
||||||
document.getElementById('perCustom').style.display = this.value === 'custom' ? 'inline' : 'none';
|
document.getElementById('perCustom').style.display = this.value === 'custom' ? 'inline' : 'none';
|
||||||
@ -1967,5 +2132,10 @@ body {
|
|||||||
})();
|
})();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<!-- Photo viewer overlay -->
|
||||||
|
<div class="photo-viewer" id="photoViewer">
|
||||||
|
<img id="photoViewerImg" src="" alt="Фото нарушения">
|
||||||
|
</div>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user