Email-уведомления: подтверждение с отправкой на почту и печать
This commit is contained in:
parent
2349fdcccb
commit
f10b8c3f75
119
index.html
119
index.html
@ -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&¤tUser.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];
|
||||
|
||||
Loading…
Reference in New Issue
Block a user