(function(){ var D={st:null,running:false,pending:false}; var BT="padding:7px 14px;border-radius:8px;border:1px solid var(--line);background:none;color:var(--txt);cursor:pointer;font-size:13px;white-space:nowrap;font-family:inherit"; function two(n){return n<10?"0"+n:""+n;} function E(s){return String(s==null?"":s).replace(/[&<>"']/g,function(c){return {"&":"&","<":"<",">":">","\"":""","'":"'"}[c];});} function ft(iso){var d=new Date(iso);if(isNaN(d))return "";return two(d.getDate())+"/"+two(d.getMonth()+1)+"/"+d.getFullYear()+" "+two(d.getHours())+":"+two(d.getMinutes());} function when(iso){var d=new Date(iso);if(isNaN(d))return "";var n=new Date();var t=two(d.getHours())+":"+two(d.getMinutes());if(d.toDateString()===n.toDateString())return t+" hôm nay";var y=new Date(n.getFullYear(),n.getMonth(),n.getDate()-1);if(d.toDateString()===y.toDateString())return t+" hôm qua";return ft(iso);} function mb(n){return Math.max(1,Math.round((+n||0)/1048576))+" MB";} function tw(m){try{if(typeof toast==="function")toast(m);}catch(e){}} function css(){if(document.getElementById("bkCss"))return;var s=document.createElement("style");s.id="bkCss";s.textContent="body.bk-mode #panelWork,body.bk-mode #panelStat,body.bk-mode #panelReport,body.bk-mode #panelSettings,body.bk-mode #panelAccounts,body.bk-mode #panelActivity,body.bk-mode #panelSecurity,body.bk-mode #panelAi,body.bk-mode #panelWk,body.bk-mode #panelBoard,body.bk-mode #panelBrowse{display:none!important}";(document.head||document.documentElement).appendChild(s);} function panel(){var p=document.getElementById("panelBk");if(p)return p;var ref=document.getElementById("panelBoard")||document.getElementById("panelSecurity");if(!ref||!ref.parentNode)return null;p=document.createElement("div");p.id="panelBk";p.className=(ref.className||"").replace(/\bhidden\b/g,"").trim()+" hidden";ref.parentNode.insertBefore(p,ref.nextSibling);p.addEventListener("click",onClick);return p;} function kp(emo,cls,lb,val,sub,col){return "
"+emo+"
"+lb+"
"+val+"
"+sub+"
";} function row(f){return "
"+ft(f.time)+" · "+mb(f.size)+"
✓ Google Drive
";} function draw(){ var p=document.getElementById("panelBk");if(!p)return; var st=D.st,files=(st&&st.files)||[],busy=D.running||D.pending,ok=!!(st&&st.ok),last=st&&st.lastOk; var conn=files.length>0||ok; var h="
"; h+="
Tự động sao lưu lúc 01:30 mỗi đêm. Bản sao lưu được mã hoá rồi lưu trên Google Drive.
"; h+="
"; h+=kp(ok||last?"✅":"⚠️",ok||last?"i-teal":"i-red","Bản gần nhất",last?when(last):"Chưa có",files.length?mb(files[0].size)+" · đã lên Drive":"Chưa có bản nào",ok||last?"var(--teal)":"var(--red)"); h+=kp("☁️",conn?"i-blue":"i-slate","Google Drive",conn?"Đã kết nối":"Chưa rõ","Thư mục NDS-Backup",conn?"var(--blue)":"var(--muted)"); h+=kp("📦","i-gold","Đang giữ",files.length+" bản","Tự xoá bản quá 14 ngày","var(--brass)"); h+="
"; if(st&&!st.ok)h+="
Lần chạy gần nhất ("+ft(st.at)+") bị lỗi: "+E(st.msg)+"
"; if(!st)h+="
Chưa có dữ liệu sao lưu. Bấm Sao lưu ngay để tạo bản đầu tiên.
"; h+="
Các bản sao lưu
"; if(!files.length)h+="
Chưa có bản nào trên Google Drive.
"; h+=files.slice(0,14).map(row).join(""); h+="
Khi server hỏng cần dựng lại: lấy bản mới nhất trong thư mục NDS-Backup trên Google Drive và làm theo hướng dẫn khôi phục (cần mật khẩu giải mã do quản trị viên giữ). Việc khôi phục không làm được trong app vì app chạy trên chính server đó.
"; p.innerHTML=h+"
"; } async function load(){ var r=null;try{r=await apiPost("backupStatus",{});}catch(e){} if(!r||r.status!==200||!r.data||!r.data.ok){var p=document.getElementById("panelBk");if(p&&!D.st)p.innerHTML="
Không tải được dữ liệu sao lưu.
";return;} D.st=r.data.st||null;D.running=!!r.data.running;D.pending=!!r.data.pending;draw(); } async function onClick(e){ var t=e.target&&e.target.closest?e.target.closest("button"):null;if(!t||!t.classList.contains("bkNow"))return; if(D.running||D.pending)return; if(!window.confirm("Tạo bản sao lưu ngay bây giờ? Mất khoảng 1 phút."))return; var r=await apiPost("backupNow",{}); if(r&&r.status===200&&r.data&&r.data.ok){tw("Đã gửi yêu cầu, bản mới xuất hiện sau khoảng 1 phút");D.pending=true;draw();}else{tw("Không gửi được yêu cầu");} } function openBk(){ css();try{boardHideAllPanels();}catch(e){} var w=document.getElementById("panelWk");if(w)w.classList.add("hidden"); document.querySelectorAll(".sb-nav a").forEach(function(x){x.classList.remove("on");}); document.body.classList.remove("nav-open"); var p=panel();if(!p)return;p.classList.remove("hidden"); var n=document.getElementById("navBk");if(n)n.classList.add("on"); try{setDashTitle("Sao lưu","Sao lưu hệ thống lên Google Drive");}catch(e){} document.body.classList.add("bk-mode");draw();load(); } function leave(){ document.body.classList.remove("bk-mode"); var p=document.getElementById("panelBk");if(p)p.classList.add("hidden"); var n=document.getElementById("navBk");if(n)n.classList.remove("on"); } function addNav(){ var s=document.getElementById("navSecurity");if(!s)return; var a=document.getElementById("navBk"); if(!a){a=document.createElement("a");a.id="navBk";a.style.display="none";a.innerHTML="💾 Sao lưu";s.parentNode.insertBefore(a,s.nextSibling);a.onclick=openBk;} var vis=getComputedStyle(s).display!=="none"; a.style.display=vis?"":"none"; } document.addEventListener("click",function(e){ if(!document.body.classList.contains("bk-mode"))return; var a=e.target.closest?e.target.closest(".sb-nav a"):null; if(a&&a.id!=="navBk")leave(); },true); addNav();setInterval(addNav,300); setInterval(function(){if(document.body.classList.contains("bk-mode")&&!document.hidden)load();},5000); })();