File manager - Edit - /home/webtrixia/demohub.webtrixia.com/offer.html
Back
<!DOCTYPE html> <html lang="bg"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Оферта — Hub</title> <link href="https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500;600;700&family=DM+Mono:wght@400;500;700&display=swap" rel="stylesheet"> <style> :root{--bg:#eef3ec;--panel:#fff;--line:#9ccc7d;--soft:#e8f3df;--ink:#151515;--muted:#5d645b;--green:#159447;--green2:#0f7a39;--red:#dc2626;--accent:#6c63ff;--fn:'DM Sans',Arial,sans-serif;--mono:'DM Mono',monospace} *{box-sizing:border-box} body{margin:0;background:var(--bg);color:var(--ink);font-family:var(--fn)} .shell{display:grid;grid-template-columns:380px minmax(760px,1fr);gap:18px;min-height:100vh;padding:18px} .editor{background:#fff;border:1px solid rgba(0,0,0,.08);border-radius:10px;padding:16px;position:sticky;top:18px;height:calc(100vh - 36px);overflow:auto} .preview{display:flex;justify-content:center;align-items:flex-start} .topbar{display:flex;gap:8px;flex-wrap:wrap;margin-bottom:14px} .btn{border:0;border-radius:8px;padding:9px 12px;font:600 12px var(--fn);cursor:pointer;background:#eef0f5;color:#1f2430} .btn.p{background:var(--green);color:#fff}.btn.a{background:var(--accent);color:#fff}.btn.d{background:#fee2e2;color:#b91c1c}.btn:disabled{opacity:.45;cursor:not-allowed} h1{font-size:18px;margin:0 0 2px}.hint{font-size:12px;color:#778070;margin:0 0 12px;line-height:1.45} .tabs{display:grid;grid-template-columns:1fr 1fr;gap:6px;margin:10px 0 14px} .tab{border:1px solid #d9e5d2;background:#f7fbf4;border-radius:8px;padding:9px 8px;text-align:center;font-size:12px;font-weight:700;cursor:pointer} .tab.on{background:var(--green);border-color:var(--green);color:#fff} .group{border-top:1px solid #edf2e8;padding-top:12px;margin-top:12px} .gtitle{font-size:11px;color:#6f786d;text-transform:uppercase;letter-spacing:.08em;font-weight:700;margin-bottom:8px} label{display:block;font-size:11px;color:#697467;text-transform:uppercase;letter-spacing:.04em;margin:9px 0 4px} input,textarea,select{width:100%;border:1px solid #dbe5d5;background:#fbfdf9;border-radius:8px;padding:9px 10px;font:13px var(--fn);outline:none;color:#121812} textarea{resize:vertical;min-height:62px} input:focus,textarea:focus,select:focus{border-color:var(--green);box-shadow:0 0 0 2px rgba(21,148,71,.1)} .grid2{display:grid;grid-template-columns:1fr 1fr;gap:8px}.grid3{display:grid;grid-template-columns:1.2fr .8fr .8fr;gap:8px} .minirow{display:grid;grid-template-columns:1fr 80px 68px 1fr 34px;gap:6px;align-items:end;margin-bottom:8px} .minirow button,.itemrow button{height:36px;border:0;border-radius:8px;background:#fee2e2;color:#b91c1c;cursor:pointer} .itemrow{display:grid;grid-template-columns:1fr 34px;gap:6px;margin-bottom:6px} .svcbox{border:1px solid #e1ebdc;background:#fbfdf9;border-radius:10px;padding:10px;margin-bottom:9px} .muted{font-size:11px;color:#7f887d}.toast{position:fixed;right:20px;bottom:20px;background:#101820;color:#fff;border-radius:10px;padding:12px 16px;font-size:13px;display:none;z-index:50} .page{width:794px;min-height:1123px;background:#fff;box-shadow:0 12px 40px rgba(0,0,0,.12);padding:58px 58px 44px;position:relative;overflow:hidden} .wm{position:absolute;inset:210px 130px auto 170px;font-size:440px;font-weight:800;color:rgba(21,148,71,.07);line-height:.7;z-index:0;pointer-events:none} .doc{position:relative;z-index:1}.logo{font-size:27px;font-weight:800;color:var(--green);letter-spacing:.03em;text-shadow:1px 1px 0 #0b5f2a;margin-bottom:64px} .title{text-align:center;margin-bottom:34px}.title h2{font-size:27px;margin:0 0 5px;font-weight:800}.title .subject{font-size:18px;font-style:italic} .lead{font-size:17px;line-height:1.55;margin-bottom:18px}.lead b{font-weight:800}.lead a{color:#1465d8;text-decoration:underline} .section-title{font-size:18px;font-weight:800;margin:16px 0 8px}.roman{font-size:18px;font-weight:800;margin:8px 0 4px;padding-left:22px} .svc{margin:8px 0 22px;padding-left:24px}.svc h3{font-size:17px;margin:0 0 8px}.svc ul{margin:0;padding-left:34px}.svc li{font-size:16px;line-height:1.45;margin:4px 0} .price{width:100%;border-collapse:collapse;margin-top:18px;font-size:15px}.price th,.price td{border:1.4px solid var(--line);padding:10px 10px;text-align:center;vertical-align:middle}.price th{font-size:17px;font-weight:800;background:#fff}.price tr:nth-child(even) td{background:var(--soft)}.price td:first-child{font-weight:800}.price .total td{background:#fff!important;font-size:18px;font-weight:800}.price .left{text-align:left}.price .small{display:block;font-weight:400;font-size:14px;margin-top:3px} .footer-note{font-weight:800;font-size:16px;margin-top:38px}.contact{font-size:14px;line-height:1.35;margin-top:8px}.contact a{color:#1465d8}.pageno{position:absolute;right:58px;bottom:42px;font:15px var(--mono)} .page.two{margin-top:18px}.page.two .logo{margin-bottom:42px}.terms{font-size:17px;line-height:1.55}.terms h3{font-size:18px;margin:16px 0 8px}.terms ul{margin:0 0 12px 20px}.terms li{margin:8px 0}.notes li{margin:6px 0}.signs{display:grid;grid-template-columns:1fr 1fr;gap:70px;margin-top:46px;font-size:16px}.sigline{border-bottom:1px dotted #333;height:28px;margin-bottom:6px}.sig-name{text-align:center;margin-top:8px} @media(max-width:1180px){.shell{grid-template-columns:1fr}.editor{position:relative;height:auto}.preview{overflow:auto;justify-content:flex-start}.page{transform-origin:top left}} @media print{ @page{size:A4;margin:0} body{background:#fff}.shell{display:block;padding:0}.editor,.toast{display:none!important}.preview{display:block}.page{width:210mm;min-height:297mm;box-shadow:none;margin:0;padding:15mm 15mm 12mm;page-break-after:always}.page.two{margin-top:0}.pageno{right:15mm;bottom:12mm}.wm{inset:58mm 34mm auto 45mm;font-size:118mm}.logo{margin-bottom:18mm}.title h2{font-size:24pt}.title .subject{font-size:15pt}.lead,.terms{font-size:14pt}.price{font-size:12pt}.price th{font-size:14pt}.price td{padding:7pt}.footer-note{margin-top:16mm} } </style> </head> <body> <div class="shell"> <aside class="editor"> <div class="topbar"> <button class="btn" onclick="location.href='index.html'">← Hub</button> <button class="btn p" onclick="saveOffer()">Запази</button> <button class="btn a" onclick="duplicateOffer()">Дублирай</button> <button class="btn" onclick="window.print()">PDF / Печат</button> </div> <h1>Редактор на оферта</h1> <p class="hint">Създай и редактирай оферти като примерите за B2B система. Всичко се пази в Hub-а.</p> <div class="tabs"> <div class="tab" id="tab_one_time" onclick="setTemplate('one_time')">Еднократна</div> <div class="tab" id="tab_monthly" onclick="setTemplate('monthly')">Месечна</div> </div> <div class="group"> <div class="gtitle">Основни данни</div> <div class="grid2"><div><label>Номер</label><input id="num"></div><div><label>Статус</label><select id="status"><option>Чакаща</option><option>Приета</option><option>Отказана</option></select></div></div> <label>Име на фирма / марка</label><input id="brand"> <label>Заглавие / предмет</label><input id="subject"> <div class="grid2"><div><label>Клиент</label><input id="client"></div><div><label>Обръщение</label><input id="greeting"></div></div> <label>Въвеждащ текст</label><textarea id="intro"></textarea> <div class="grid3"><div><label>Дата</label><input type="date" id="issue_date"></div><div><label>Валидност дни</label><input type="number" id="valid_days"></div><div><label>Срок дни</label><input type="number" id="work_days"></div></div> </div> <div class="group"> <div class="gtitle">Услуги и функционалности</div> <div id="svcEditor"></div> <button class="btn" style="width:100%" onclick="addGroup()">+ Добави група</button> </div> <div class="group"> <div class="gtitle">Ценова листа</div> <div id="rowsEditor"></div> <button class="btn" style="width:100%" onclick="addRow()">+ Добави ред</button> <p class="muted">Сумата се изчислява от колоната „Крайна цена“. Ако редът е текстов, остави 0.</p> </div> <div class="group"> <div class="gtitle">Условия и бележки</div> <label>Плащане</label><textarea id="payment"></textarea> <label>Допълнителни бележки</label><textarea id="notes"></textarea> <div class="grid2"><div><label>Изготвил</label><input id="prepared_by"></div><div><label>Приел</label><input id="accepted_by"></div></div> <label>Контакти</label><textarea id="contacts"></textarea> </div> </aside> <main class="preview"> <div> <section class="page"> <div class="wm">W</div> <div class="doc" id="page1"></div> <div class="pageno">/ 1 /</div> </section> <section class="page two"> <div class="doc" id="page2"></div> <div class="pageno">/ 2 /</div> </section> </div> </main> </div> <div class="toast" id="toast"></div> <script> 'use strict'; const API=(function(){const base=window.location.origin+window.location.pathname.replace(/offer\.html$/,'').replace(/\/$/,'');return base+'/api.php';})(); const qs=new URLSearchParams(location.search); let offerId=qs.get('id')||''; let data={}; function today(){return new Date().toISOString().slice(0,10);} function numDefault(){return String(Math.floor(400+Math.random()*500)).padStart(10,'0');} function money(n){return '€ '+Number(n||0).toLocaleString('de-DE',{minimumFractionDigits:2,maximumFractionDigits:2});} function esc(s){return String(s==null?'':s).replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"');} function nl(s){return esc(s).replace(/\n/g,'<br>');} function toast(m){const t=document.getElementById('toast');t.textContent=m;t.style.display='block';setTimeout(()=>t.style.display='none',2600);} function dateBg(s){if(!s)return '';const d=new Date(s+'T00:00:00');return d.toLocaleDateString('bg-BG',{day:'2-digit',month:'2-digit',year:'numeric'})+'г.';} async function af(action,method,body,extra){method=method||'GET';extra=extra||'';const o={method,headers:{'Content-Type':'application/json'}};if(body)o.body=JSON.stringify(body);const r=await fetch(API+'?action='+action+extra,o);const j=await r.json();if(!j.ok)throw new Error(j.error||'Грешка');return j.data;} function template(type){ const monthly=type==='monthly'; return { type, num: monthly?'0000000428':'0000000427', status:'Чакаща', brand:'Име на фирма', subject: monthly?'Оферта за система и месечна поддръжка':'Оферта за изработка на система', client:'', greeting:'Уважаеми,', intro:'В офертата са включени следните функционалности:', issue_date:'2026-07-07', valid_days:30, work_days:30, groups:[ {title:'I. Изработка',items:[ {title:'1. Дизайн на б2б системата и уеб сайта:',bullets:['Уникален и модерен дизайн','Адаптивност с устройства','Удобен потребителски и администраторски интерфейс']}, {title:'2. Интеграции:',bullets:['Интеграция с куриерски фирми на B2B системата','Интеграция на банкови и картови плащания']}, {title:'3. Обучение:',bullets:['Включено обучение за управление на съдържанието и основните процеси.']} ]} ], rows: monthly?[ {service:'Хостинг и домейн',price:'€ 200,00\n(на година)',discount:'-',final:'КЛИЕНТЪТ\nРАЗПОЛАГА',amount:0}, {service:'Доработки по дизайна на сайта',price:'€ 1300.00\n(еднократно)',discount:'- 55%',final:'€ 585,00\n(еднократно)',amount:585}, {service:'B2B система месечна услуга',price:'€ 150,00\n(на месец)',discount:'- 0%',final:'€ 150,00\n(месец)',amount:150,monthly:1}, {service:'Дигитален продуктов каталог',price:'€ 450,00',discount:'-100%',final:'€ 00,00',amount:0}, {service:'Месечна поддръжка',price:'€ 120,00',discount:'-100%',final:'€ 00,00',amount:0,monthly:1} ]:[ {service:'Хостинг и домейн',price:'€ 200,00\n(на година)',discount:'-',final:'КЛИЕНТЪТ\nРАЗПОЛАГА',amount:0}, {service:'Доработки по дизайна на сайта',price:'€ 1300.00\n(еднократно)',discount:'- 55%',final:'€ 585,00\n(еднократно)',amount:585}, {service:'Изработка на B2B система',price:'€ 3200,00\n(еднократно)',discount:'- 50%',final:'€ 1600,00\n(еднократно)',amount:1600}, {service:'Дигитален продуктов каталог',price:'€ 450,00',discount:'-100%',final:'€ 00,00',amount:0}, {service:'Месечна поддръжка',price:'€ 120,00',discount:'-50%',final:'€ 60,00',amount:60,monthly:1} ], payment:'При приемане на офертата се заплаща 50% авансово с цел капаро.\nОфертата е валидна в срок от 30 дни след датата на издаването.', notes:'Поддръжката включва - 7/24 мониторинг на платформата и сайта, отстраняване на нередности, сменяне на банери, актуализиране на системата всяка седмица, ежедневен бекъп на системата, сканиране на системата всяка седмица за злонамерен достъп.', prepared_by:'', accepted_by:'', contacts:'Всички цени са без ДДС !' }; } function setTemplate(type){ if(!offerId && (!data.type || confirm('Да заредя шаблона и да заменя текущите данни?'))){ data=template(type); fillEditor(); renderAll(); } else { data.type=type; fillEditor(); renderAll(); } } function readEditor(){ ['num','status','brand','subject','client','greeting','intro','issue_date','valid_days','work_days','payment','notes','prepared_by','accepted_by','contacts'].forEach(id=>data[id]=document.getElementById(id).value); data.groups=[...document.querySelectorAll('.svcbox')].map(box=>({ title:box.querySelector('[data-k=gt]').value, items:[...box.querySelectorAll('.svcitem')].map(it=>({ title:it.querySelector('[data-k=it]').value, bullets:[...it.querySelectorAll('[data-k=bul]')].map(x=>x.value).filter(Boolean) })) })); data.rows=[...document.querySelectorAll('.minirow')].map(r=>({ service:r.querySelector('[data-k=service]').value, price:r.querySelector('[data-k=price]').value, discount:r.querySelector('[data-k=discount]').value, final:r.querySelector('[data-k=final]').value, amount:parseFloat(r.querySelector('[data-k=amount]').value)||0, monthly:r.querySelector('[data-k=monthly]').checked?1:0 })); } function fillEditor(){ if(!data.brand)data.brand='Име на фирма'; document.getElementById('tab_one_time').classList.toggle('on',data.type!=='monthly'); document.getElementById('tab_monthly').classList.toggle('on',data.type==='monthly'); ['num','status','brand','subject','client','greeting','intro','issue_date','valid_days','work_days','payment','notes','prepared_by','accepted_by','contacts'].forEach(id=>document.getElementById(id).value=data[id]||''); renderGroupEditor(); renderRowsEditor(); } function bindLive(){document.querySelectorAll('input,textarea,select').forEach(el=>{el.oninput=()=>{readEditor();renderAll();};el.onchange=()=>{readEditor();renderAll();};});} function renderGroupEditor(){ document.getElementById('svcEditor').innerHTML=(data.groups||[]).map((g,gi)=> '<div class="svcbox"><label>Група</label><input data-k="gt" value="'+esc(g.title)+'">'+ '<div id="items_'+gi+'">'+(g.items||[]).map((it,ii)=>itemHtml(gi,ii,it)).join('')+'</div>'+ '<button class="btn" onclick="addItem('+gi+')">+ Подточка</button> <button class="btn d" onclick="delGroup('+gi+')">Изтрий група</button></div>' ).join(''); bindLive(); } function itemHtml(gi,ii,it){ return '<div class="svcitem" style="border-top:1px solid #edf2e8;margin-top:9px;padding-top:9px"><label>Заглавие</label><input data-k="it" value="'+esc(it.title)+'">'+ '<label>Булети</label>'+(it.bullets||[]).map((b,bi)=>'<div class="itemrow"><input data-k="bul" value="'+esc(b)+'"><button onclick="delBullet('+gi+','+ii+','+bi+')">×</button></div>').join('')+ '<button class="btn" onclick="addBullet('+gi+','+ii+')">+ Булет</button> <button class="btn d" onclick="delItem('+gi+','+ii+')">Изтрий</button></div>'; } function renderRowsEditor(){ document.getElementById('rowsEditor').innerHTML=(data.rows||[]).map((r,i)=> '<div class="minirow"><div><label>Услуга</label><textarea data-k="service">'+esc(r.service)+'</textarea></div>'+ '<div><label>Цена</label><textarea data-k="price">'+esc(r.price)+'</textarea></div>'+ '<div><label>Отст.</label><input data-k="discount" value="'+esc(r.discount)+'"></div>'+ '<div><label>Крайна</label><textarea data-k="final">'+esc(r.final)+'</textarea><input data-k="amount" type="number" step="0.01" value="'+(r.amount||0)+'" title="Сума за общо"><label style="text-transform:none;letter-spacing:0"><input data-k="monthly" type="checkbox" '+(r.monthly?'checked':'')+' style="width:auto"> месечно</label></div>'+ '<button onclick="delRow('+i+')">×</button></div>' ).join(''); bindLive(); } function addGroup(){readEditor();data.groups.push({title:'Нова група',items:[{title:'Нова услуга:',bullets:['Описание']} ]});renderGroupEditor();renderAll();} function delGroup(i){readEditor();data.groups.splice(i,1);renderGroupEditor();renderAll();} function addItem(gi){readEditor();data.groups[gi].items.push({title:'Нова подточка:',bullets:['Описание']});renderGroupEditor();renderAll();} function delItem(gi,ii){readEditor();data.groups[gi].items.splice(ii,1);renderGroupEditor();renderAll();} function addBullet(gi,ii){readEditor();data.groups[gi].items[ii].bullets.push('Нов булет');renderGroupEditor();renderAll();} function delBullet(gi,ii,bi){readEditor();data.groups[gi].items[ii].bullets.splice(bi,1);renderGroupEditor();renderAll();} function addRow(){readEditor();data.rows.push({service:'Нова услуга',price:'€ 0,00',discount:'-',final:'€ 0,00',amount:0});renderRowsEditor();renderAll();} function delRow(i){readEditor();data.rows.splice(i,1);renderRowsEditor();renderAll();} function totals(){const one=(data.rows||[]).filter(r=>!r.monthly).reduce((a,r)=>a+(+r.amount||0),0);const mon=(data.rows||[]).filter(r=>r.monthly).reduce((a,r)=>a+(+r.amount||0),0);return {one,mon};} function validDate(){const d=new Date((data.issue_date||today())+'T00:00:00');d.setDate(d.getDate()+(parseInt(data.valid_days)||30));return d.toISOString().slice(0,10);} function rowsHtml(){const t=totals();return '<table class="price"><thead><tr><th>Услуга</th><th>Цена</th><th>Отстъпка</th><th>Крайна цена</th></tr></thead><tbody>'+ (data.rows||[]).map(r=>'<tr><td>'+nl(r.service)+'</td><td>'+nl(r.price)+'</td><td>'+nl(r.discount)+'</td><td>'+nl(r.final)+'</td></tr>').join('')+ '<tr class="total"><td>Общо:</td><td colspan="3">'+money(t.one)+(t.mon?'<span class="small">Месечно: '+money(t.mon)+'</span>':'')+'</td></tr></tbody></table>'; } function renderAll(){ const t=totals(); const brand=(data.brand||'Име на фирма').trim()||'Име на фирма'; const mark=(brand.charAt(0)||'О').toUpperCase(); document.querySelectorAll('.wm').forEach(el=>{el.textContent=mark;}); document.getElementById('page1').innerHTML= '<div class="logo">'+esc(brand)+'</div><div class="title"><h2>Оферта № '+esc(data.num||'')+'</h2><div class="subject">'+esc(data.subject||'')+'</div></div>'+ '<div class="lead"><b>До:</b> '+esc(data.client||'')+'</div><div class="lead">'+esc(data.greeting||'')+'</div><div class="lead">'+nl(data.intro||'')+'</div>'+ (data.groups||[]).map(g=>'<div class="roman">'+esc(g.title)+'</div>'+(g.items||[]).map(it=>'<div class="svc"><h3>'+esc(it.title)+'</h3><ul>'+(it.bullets||[]).map(b=>'<li>'+esc(b)+'</li>').join('')+'</ul></div>').join('')).join('')+ '<div class="section-title">4. Ценова листа:</div>'+rowsHtml()+ '<div class="footer-note">'+nl((data.contacts||'').split('\\n')[0]||'Всички цени са без ДДС !')+'</div><div class="contact">'+nl((data.contacts||'').split('\\n').slice(1).join('\\n'))+'</div>'; document.getElementById('page2').innerHTML= '<div class="terms"><h3>5. Срок за изработка:</h3><ul><li>Изпълнителят предоставя срок за изработка до '+esc(data.work_days||30)+' работни дни.</li></ul>'+ '<h3>6. Плащане и срокове:</h3><ul>'+(data.payment||'').split('\\n').filter(Boolean).map(x=>'<li>'+esc(x)+'</li>').join('')+ '<li>Офертата се издава на дата: '+dateBg(data.issue_date||today())+'</li><li>Офертата е валидна до: '+dateBg(validDate())+'</li></ul>'+ '<h3>8. Допълнителни бележки:</h3><ul class="notes">'+(data.notes||'').split('\\n').filter(Boolean).map(x=>'<li>'+esc(x)+'</li>').join('')+'</ul></div>'+ '<div class="signs"><div><div>Изготвил:</div><div class="sigline"></div><div class="sig-name">/ '+esc(data.prepared_by||'')+' /</div></div><div><div>Приел:</div><div class="sigline"></div><div class="sig-name">/ '+esc(data.accepted_by||'')+' /</div></div></div>'+ '<div class="footer-note" style="margin-top:70px">'+nl((data.contacts||'').split('\\n')[0]||'Всички цени са без ДДС !')+'</div><div class="contact">'+nl((data.contacts||'').split('\\n').slice(1).join('\\n'))+'</div>'; return t; } async function saveOffer(){ try{ readEditor(); const t=totals(); const saved=await af('offers','POST',{id:offerId||undefined,num:data.num,client:data.client,service:data.subject,total:t.one,status:data.status,offer_type:data.type,details:data}); offerId=saved.id; history.replaceState(null,'','offer.html?id='+encodeURIComponent(offerId)); toast('Офертата е запазена'); }catch(e){toast('Грешка: '+e.message);} } async function duplicateOffer(){readEditor();offerId='';data.num=numDefault();fillEditor();renderAll();await saveOffer();} async function init(){ if(!(await moduleGuard('offers','Офертите')))return; if(offerId){ try{const row=await af('offers','GET',null,'&id='+encodeURIComponent(offerId));data=row.details?JSON.parse(row.details):template(row.offer_type||'one_time');data.num=row.num||data.num;data.client=row.client||data.client;data.subject=row.service||data.subject;data.status=row.status||data.status;}catch(e){toast('Грешка: '+e.message);data=template(qs.get('type')||'one_time');} } else data=template(qs.get('type')||'one_time'); if(!data.issue_date)data.issue_date=today(); if(!data.num)data.num=numDefault(); fillEditor(); renderAll(); } init(); async function moduleGuard(key,label){ try{ await syncLicenseFromMaster(); const r=await fetch(API+'?action=branding_settings'); const j=await r.json(); const d=(j&&j.data)||{}; if(d.license_state==='locked'||d.license_state==='invalid'){ renderBlocked(d.license_message||'Лицензът не е активен.'); return false; } if(d.modules_enabled&&Object.prototype.hasOwnProperty.call(d.modules_enabled,key)&&!Number(d.modules_enabled[key])){ renderBlocked((label||'Модулът')+' е изключен за тази инсталация.'); return false; } }catch(e){} return true; } async function syncLicenseFromMaster(){ try{ const c=await af('license_client_config'); if(!c||!c.verify_url)return; const rr=await fetch(c.verify_url,{cache:'no-store',mode:'cors'}); const payload=await rr.json(); if(payload&&payload.state) await af('license_sync','POST',{payload}); }catch(e){} } function renderBlocked(msg){ document.body.innerHTML='<div style="min-height:100vh;display:flex;align-items:center;justify-content:center;padding:24px;background:#0a0a12;color:#ececf5;font-family:DM Sans,sans-serif"><div style="max-width:460px;text-align:center;background:rgba(255,255,255,.04);border:1px solid rgba(255,255,255,.1);border-radius:18px;padding:38px 30px"><h2 style="font-size:22px;margin-bottom:10px">Модулът е заключен</h2><p style="color:#a0a0c0;font-size:14px;line-height:1.6">'+esc(msg)+'</p></div></div>'; } </script> </body> </html>
| ver. 1.4 |
Github
|
.
| PHP 8.2.31 | Generation time: 0 |
proxy
|
phpinfo
|
Settings