Files
Bridge-and-Join-s/internal/lkgateway/web/templates/admin_prepare.html
T

64 lines
5.4 KiB
HTML

{{define "content"}}
<style>
.prep-head { text-align:center; padding:8px 0 4px; }
.prep-head h1 { font-size:26px; font-weight:720; letter-spacing:-0.02em; margin:0 0 6px; }
.prep-head p { color:var(--muted); margin:0 auto; max-width:620px; }
.prep { max-width:680px; margin:24px auto 0; }
.prep-row { display:grid; grid-template-columns:26px 1fr; gap:4px 10px; padding:12px 0; border-bottom:1px solid var(--border); }
.prep-row:last-child { border-bottom:0; }
.prep-row .ic { font-size:16px; line-height:22px; text-align:center; }
.prep-row b { font-weight:620; }
.prep-row .muted { font-size:13px; }
.prep-bar { height:6px; border-radius:3px; background:var(--card-2); overflow:hidden; margin:6px 0 0; }
.prep-bar i { display:block; height:100%; width:100%; background:var(--accent); transform-origin:left center; transform:scaleX(0); transition:transform .4s ease; }
.prep-foot { display:flex; align-items:center; justify-content:space-between; gap:12px; margin-top:16px; flex-wrap:wrap; }
@keyframes prepspin { to { transform:rotate(360deg); } }
.spin { display:inline-block; width:14px; height:14px; border:2px solid var(--accent-weak); border-top-color:var(--accent); border-radius:50%; animation:prepspin .8s linear infinite; vertical-align:-2px; }
@media (prefers-reduced-motion: reduce) { .spin { animation:none; } .prep-bar i { transition:none; } }
</style>
<div class="prep-head">
<h1>Подготовка модулей</h1>
<p>Ключ принят: <b>{{.Tenant}}</b>. bj ставит и запускает модули, которые входят в вашу лицензию, — затем откроется мастер настройки.</p>
</div>
<div class="card prep">
{{if .Flash}}<p style="margin:0 0 6px;color:var(--ok)">✓ {{.Flash}}</p>{{end}}
<p class="muted" style="margin:0 0 4px;font-size:13px">Лицензия: план {{.Plan}}, {{.Until}}</p>
<div id="prep-rows"><p class="muted" style="margin:12px 0">Проверяю состав лицензии…</p></div>
<div id="prep-prog" style="display:none;margin-top:8px"><span class="muted" id="prep-stage" style="font-size:13px"></span><div class="prep-bar"><i id="prep-fill"></i></div></div>
<div class="prep-foot">
<span id="prep-sum" style="font-weight:600"></span>
<a class="btn" id="prep-next" href="{{.Next}}" style="text-decoration:none;display:none">Перейти к настройке →</a>
</div>
</div>
<script>
(function(){
var rows=document.getElementById('prep-rows'), sum=document.getElementById('prep-sum'), nxt=document.getElementById('prep-next');
var prog=document.getElementById('prep-prog'), stage=document.getElementById('prep-stage'), fill=document.getElementById('prep-fill');
var next={{.Next}}, started=false, redirect=null;
function esc(s){return String(s==null?'':s).replace(/[&<>"]/g,function(c){return{'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;'}[c]})}
var ic={ok:'<span style="color:var(--ok)">✓</span>',run:'<span class="spin" aria-label="идёт"></span>',wait:'<span class="muted">○</span>',warn:'<span style="color:var(--warn)">⚠</span>',err:'<span style="color:var(--err)">✗</span>',info:'<span class="muted">ⓘ</span>'};
function mb(n){return (n/1048576).toFixed(1).replace('.',',')+' МБ'}
function draw(d){
rows.innerHTML=d.items.map(function(it){return '<div class="prep-row"><div class="ic">'+ic[it.state]+'</div><div><b>'+esc(it.title)+'</b>'+(it.detail?'<br><span class="muted">'+esc(it.detail)+'</span>':'')+'</div></div>'}).join('');
if(d.running && d.stage){ prog.style.display=''; stage.textContent=d.stage+(d.total?' — '+mb(d.done)+' из '+mb(d.total):''); fill.style.transform='scaleX('+(d.total?Math.min(1,d.done/d.total):0.15)+')'; }
else prog.style.display='none';
var bad=d.items.filter(function(it){return it.state==='err'}).length, warn=d.items.filter(function(it){return it.state==='warn'}).length;
if(d.running || d.busy || (d.pending && !d.finished)){ sum.innerHTML='<span class="muted" style="font-weight:400">Ставлю и запускаю модули… обычно меньше минуты</span>'; nxt.style.display='none'; return false; }
nxt.style.display='';
if(bad){ sum.innerHTML='<span style="color:var(--err)">✗ Не всё установилось</span> <span class="muted" style="font-weight:400">— продолжить можно, модули поставятся из «Настройка → Обновления»</span>'; return true; }
if(warn){ sum.innerHTML='<span style="color:var(--ok)">✓ Готово</span> <span class="muted" style="font-weight:400">— есть замечание (⚠), продолжать можно</span>'; return true; }
sum.innerHTML='<span style="color:var(--ok)">✓ Модули готовы</span> <span class="muted" style="font-weight:400">— открываю мастер настройки…</span>';
if(!redirect) redirect=setTimeout(function(){ location.href=next; }, 2500);
return true;
}
function poll(){
fetch('/admin/setup/prepare/status',{cache:'no-store'}).then(function(r){return r.json()}).then(function(d){
if(!started && d.pending && !d.running && !d.finished){ started=true; fetch('/admin/setup/prepare/start',{method:'POST',cache:'no-store'}).then(function(){ setTimeout(poll,600); }); draw(d); return; }
if(!draw(d)) setTimeout(poll,1500);
}).catch(function(){ setTimeout(poll,3000); });
}
poll();
})();
</script>
{{end}}