Email-уведомления: подтверждение с отправкой на почту и печать

This commit is contained in:
Dauren777 2026-06-03 12:04:37 +00:00
parent 2349fdcccb
commit f10b8c3f75

View File

@ -299,6 +299,10 @@ body{
<label>Ваше ФИО</label>
<input type="text" id="regName" placeholder="Фамилия И.О.">
</div>
<div class="form-group">
<label>Ваш Email <span style="font-weight:400;color:var(--gray-500)">(для уведомлений)</span></label>
<input type="email" id="regEmail" placeholder="email@company.kz">
</div>
<div class="form-group">
<label>Должность / роль</label>
<select id="regRole">
@ -363,6 +367,9 @@ body{
<div class="fg"><label>ФИО руководителя работ</label><input id="pabSupervisor" placeholder="ФИО"></div>
<div class="fg"><label>Должность руководителя</label><input id="pabSupervisorRole" placeholder="Должность"></div>
</div>
<div class="header-grid col2" style="margin-top:12px">
<div class="fg"><label>Email для уведомления</label><input type="email" id="pabEmail" placeholder="Укажите email для получения подтверждения"></div>
</div>
<div class="form-group" style="margin-top:14px;margin-bottom:0">
<label>Отметка для передачи в отдел БиОТ ДПБ</label>
<div class="overall-toggle">
@ -390,7 +397,14 @@ body{
<button class="btn btn-primary" onclick="submitAudit()">💾 Сохранить аудит</button>
<button class="btn btn-outline" onclick="resetAuditForm()">🗑️ Очистить форму</button>
</div>
<div id="formSuccess" class="form-success">✅ Аудит сохранён! Данные доступны в Дашборде и Истории.</div>
<div id="formSuccess" class="form-success" style="display:none">
<div style="font-size:18px;margin-bottom:8px">✅ Аудит сохранён!</div>
<div id="successDetail" style="font-size:13px;color:var(--ink);margin-bottom:14px"></div>
<div style="display:flex;gap:10px;flex-wrap:wrap">
<button class="btn btn-primary btn-sm" onclick="sendEmailConfirm()">✉️ Отправить подтверждение на email</button>
<button class="btn btn-outline btn-sm" onclick="printConfirm()">🖨️ Распечатать</button>
</div>
</div>
</div>
</div>
@ -533,7 +547,7 @@ function saveRegisteredUsers(data){localStorage.setItem('safetyAuditRegisteredUs
function getAllUsers(){return{...getRegisteredUsers(),...PREDEFINED_USERS}}
// ========== STATE ==========
let currentUser=null,currentPanel='newAudit',editId=null,charts={};
let currentUser=null,currentPanel='newAudit',editId=null,charts={},lastSubmitted=null;
function isAdmin(){return currentUser&&currentUser.login==='admin'}
@ -552,6 +566,7 @@ function init(){
document.getElementById('regLogin').addEventListener('keydown',function(e){if(e.key==='Enter')doRegister();});
document.getElementById('regPass').addEventListener('keydown',function(e){if(e.key==='Enter')doRegister();});
document.getElementById('regName').addEventListener('keydown',function(e){if(e.key==='Enter')doRegister();});
document.getElementById('regEmail').addEventListener('keydown',function(e){if(e.key==='Enter')doRegister();});
}
init();
@ -759,6 +774,7 @@ function submitAudit(){
observerRole:document.getElementById('pabObserverRole').value.trim(),
supervisor:document.getElementById('pabSupervisor').value.trim(),
supervisorRole:document.getElementById('pabSupervisorRole').value.trim(),
email:document.getElementById('pabEmail').value.trim()||currentUser.email||'',
overallSafe:overallSafe,
categories:cats,
totalViolations:totalViolations,
@ -772,10 +788,8 @@ function submitAudit(){
else{audits.unshift(entry);}
saveAudits(audits);
resetAuditForm();
const s=document.getElementById('formSuccess');
s.style.display='block';
setTimeout(()=>s.style.display='none',3000);
window.scrollTo({top:0,behavior:'smooth'});
lastSubmitted=entry;
showSuccess(entry);
}
function resetAuditForm(){
@ -790,6 +804,7 @@ function resetAuditForm(){
document.getElementById('pabObserverRole').value='';
document.getElementById('pabSupervisor').value='';
document.getElementById('pabSupervisorRole').value='';
document.getElementById('pabEmail').value=currentUser?currentUser.email||'':'';
setOverall('safe');
editId=null;
CATEGORIES.forEach(cat=>{
@ -809,6 +824,88 @@ function resetAuditForm(){
document.getElementById('formSuccess').style.display='none';
}
function showSuccess(entry){
const catsWithVio=CATEGORIES.filter(cat=>{
const c=entry.categories&&entry.categories[cat.id];
return c&&c.items.length>0;
}).map(c=>c.title).join(', ')||'все категории безопасны';
document.getElementById('successDetail').innerHTML=`
<b>Бланк №${entry.number||'—'}</b> | ${entry.date} | ${entry.timeStart||'—'}—${entry.timeEnd||'—'}<br>
Место: ${entry.location} | Тип: ${entry.workType||'—'}<br>
Наблюдатель: ${entry.observer} | Статус: <b>${entry.overallSafe?'ВСЕ БЕЗОПАСНО':'ВЫЯВЛЕНО '+entry.totalViolations+' НАРУШЕНИЙ'}</b><br>
Категории с нарушениями: ${catsWithVio}
${entry.email?'<br>Копия отправляется на: <b>'+entry.email+'</b>':''}`;
const s=document.getElementById('formSuccess');
s.style.display='block';
window.scrollTo({top:s.offsetTop-80,behavior:'smooth'});
setTimeout(()=>{if(s.style.display==='block')s.style.display='none';},30000);
}
function sendEmailConfirm(){
if(!lastSubmitted)return;
const e=lastSubmitted;
const emailTo=e.email||currentUser.email||'';
const subject='ПАБ №'+(e.number||'—')+' от '+e.date;
const body=`ПОДТВЕРЖДЕНИЕ ПОВЕДЕНЧЕСКОГО АУДИТА БЕЗОПАСНОСТИ (ПАБ)
Бланк ПАБ №: ${e.number||'—'}
Дата: ${e.date}
Время: ${e.timeStart||'—'} — ${e.timeEnd||'—'}
Место: ${e.location}
Тип работы: ${e.workType||'—'}
Наблюдатель: ${e.observer} (${e.observerRole||'—'})
Руководитель: ${e.supervisor||'—'} (${e.supervisorRole||'—'})
Статус: ${e.overallSafe?'ВСЕ БЕЗОПАСНО':'ВЫЯВЛЕНО НАРУШЕНИЙ: '+e.totalViolations}
=== РЕЗУЛЬТАТЫ ПО КАТЕГОРИЯМ ===
${CATEGORIES.map(cat=>{
const cdata=e.categories&&e.categories[cat.id];
const items=cdata?cdata.items:[];
return cat.title+': '+(items.length===0?'БЕЗОПАСНО':items.length+' наруш.: '+items.map(it=>it.item+(it.other?' ('+it.other+')':'')).join('; '));
}).join('\n')}
${e.violations&&e.violations.length>0?'\n=== НЕСООТВЕТСТВИЯ ===\n'+e.violations.map((v,i)=>(i+1)+'. '+v.nc+' | Исп: '+v.executor+' | Меры: '+v.measure+' | Отв: '+v.responsible).join('\n'):''}
Аудит проведён в системе ПАБ. ${e.overallSafe?'Нарушений не выявлено.':'Требуются корректирующие меры.'}`;
if(emailTo&&emailTo.includes('@')){
window.location.href='mailto:'+encodeURIComponent(emailTo)+'?subject='+encodeURIComponent(subject)+'&body='+encodeURIComponent(body);
}else{
alert('Не указан email для отправки. Укажите email в форме аудита или при регистрации.');
}
}
function printConfirm(){
if(!lastSubmitted)return;
const e=lastSubmitted;
const w=window.open('','_blank','width=700,height=800');
w.document.write(`<!DOCTYPE html><html><head><meta charset="utf-8"><title>ПАБ №${e.number||'—'}</title>
<style>body{font:14px/1.5 Arial,sans-serif;max-width:700px;margin:40px auto;padding:20px}
h1{font-size:20px}h2{font-size:16px;border-bottom:1px solid #ccc;padding-bottom:6px}
table{width:100%;border-collapse:collapse;margin:12px 0}td{padding:6px 8px;border:1px solid #ddd}
.mark{width:16px;text-align:center}
@media print{body{margin:0;padding:10px}button{display:none}}</style></head><body>
<button onclick="window.print()" style="padding:8px 20px;font-size:16px;margin-bottom:20px">🖨️ Печать</button>
<h1>БЛАНК ПАБ №${e.number||'—'} от ${e.date}</h1>
<p><b>Время:</b> ${e.timeStart||'—'} — ${e.timeEnd||'—'} | <b>Место:</b> ${e.location}</p>
<p><b>Тип работы:</b> ${e.workType||'—'} | <b>Наблюдаемых:</b> ${e.workerCount||0}</p>
<p><b>Наблюдатель:</b> ${e.observer} (${e.observerRole||'—'})</p>
<p><b>Руководитель:</b> ${e.supervisor||'—'} (${e.supervisorRole||'—'})</p>
<p><b>Статус:</b> ${e.overallSafe?'ВСЕ БЕЗОПАСНО':'ВЫЯВЛЕНО '+e.totalViolations+' НАРУШЕНИЙ'}</p>
${CATEGORIES.map(cat=>{
const cdata=e.categories&&e.categories[cat.id];
const items=cdata?cdata.items:[];
let rows='';
items.forEach(it=>{rows+='<tr><td class="mark"></td><td>'+it.item+(it.other?' — '+it.other:'')+'</td></tr>';});
return '<h2>'+cat.title+' — '+(items.length===0?'БЕЗОПАСНО':items.length+' наруш.')+'</h2><table>'+rows+'</table>';
}).join('')}
${e.violations&&e.violations.length>0?'<h2>НЕСООТВЕТСТВИЯ</h2><table><tr><th></th><th>Несоответствие</th><th>Исполнитель</th><th>Меры</th><th>Ответственный</th><th>Дата</th></tr>'+e.violations.map((v,i)=>'<tr><td>'+(i+1)+'</td><td>'+v.nc+'</td><td>'+v.executor+'</td><td>'+v.measure+'</td><td>'+v.responsible+'</td><td>'+v.date+'</td></tr>').join('')+'</table>':''}
</body></html>`);
w.document.close();
}
// ========== DATA STORAGE ==========
function getAudits(){try{return JSON.parse(localStorage.getItem('safetyAudits')||'[]')}catch(e){return[]}}
function saveAudits(data){localStorage.setItem('safetyAudits',JSON.stringify(data))}
@ -827,6 +924,7 @@ function doRegister(){
const login=document.getElementById('regLogin').value.trim().toLowerCase();
const pass=document.getElementById('regPass').value.trim();
const name=document.getElementById('regName').value.trim();
const email=document.getElementById('regEmail').value.trim();
const role=document.getElementById('regRole').value;
const err=document.getElementById('regError');
const ok=document.getElementById('regSuccess');
@ -834,16 +932,18 @@ function doRegister(){
if(!login||login.length<2){err.textContent='Логин должен быть минимум 2 символа';err.style.display='block';return;}
if(!pass||pass.length<3){err.textContent='Пароль должен быть минимум 3 символа';err.style.display='block';return;}
if(!name){err.textContent='Укажите ФИО';err.style.display='block';return;}
if(!email||!email.includes('@')){err.textContent='Укажите корректный Email';err.style.display='block';return;}
const allUsers=getAllUsers();
if(allUsers[login]){err.textContent='Такой логин уже занят';err.style.display='block';return;}
err.style.display='none';
const users=getRegisteredUsers();
users[login]={pass:pass,name:name,role:role};
users[login]={pass:pass,name:name,email:email,role:role};
saveRegisteredUsers(users);
ok.style.display='block';
document.getElementById('regLogin').value='';
document.getElementById('regPass').value='';
document.getElementById('regName').value='';
document.getElementById('regEmail').value='';
document.getElementById('loginUser').value=login;
setTimeout(()=>{switchLoginTab('login');ok.style.display='none';},2000);
}
@ -865,13 +965,15 @@ function doLogout(){
document.getElementById('loginScreen').style.display='flex';
document.getElementById('appScreen').style.display='none';
document.getElementById('loginUser').value='';document.getElementById('loginPass').value='';
document.getElementById('regLogin').value='';document.getElementById('regPass').value='';document.getElementById('regName').value='';
document.getElementById('regLogin').value='';document.getElementById('regPass').value='';document.getElementById('regName').value='';document.getElementById('regEmail').value='';
document.getElementById('loginError').style.display='none';document.getElementById('regError').style.display='none';document.getElementById('regSuccess').style.display='none';
}
function showApp(){
document.getElementById('loginScreen').style.display='none';
document.getElementById('appScreen').style.display='block';
document.getElementById('displayName').textContent=currentUser.login+' ('+currentUser.role+')';
document.getElementById('pabObserver').value=currentUser.name;
document.getElementById('pabEmail').value=currentUser.email||'';
switchPanel('newAudit',document.querySelector('[data-panel="newAudit"]'));
}
@ -1049,6 +1151,7 @@ function editAudit(id){
document.getElementById('pabObserverRole').value=a.observerRole||'';
document.getElementById('pabSupervisor').value=a.supervisor||'';
document.getElementById('pabSupervisorRole').value=a.supervisorRole||'';
document.getElementById('pabEmail').value=a.email||'';
setOverall(a.overallSafe?'safe':'danger');
CATEGORIES.forEach(cat=>{
const cdata=a.categories&&a.categories[cat.id];