add kerio format support

This commit is contained in:
2026-07-17 11:42:12 +07:00
parent ccd8e8eb1b
commit 11175b4e31
4 changed files with 155 additions and 33 deletions
+8 -5
View File
@@ -72,6 +72,7 @@
.pill .c{width:8px;height:8px;border-radius:50%}
.pill.create .c{background:var(--create)} .pill.warn .c{background:var(--warn)}
.pill.exists .c{background:var(--exists)} .pill.error .c{background:var(--error)}
.pill.skip .c{background:var(--exists)}
.tablewrap{max-height:340px;overflow:auto;border:1px solid var(--border);border-radius:9px;margin-top:4px}
table{width:100%;border-collapse:collapse;font-family:var(--mono);font-size:12px}
thead th{position:sticky;top:0;background:var(--panel2);text-align:left;color:var(--muted);
@@ -83,6 +84,7 @@
.st.create{color:var(--create)} .st.create::before{background:var(--create)}
.st.warn{color:var(--warn)} .st.warn::before{background:var(--warn)}
.st.exists{color:var(--exists)} .st.exists::before{background:var(--exists)}
.st.skip{color:var(--exists)} .st.skip::before{background:var(--exists)}
.st.error{color:var(--error)} .st.error::before{background:var(--error)}
.note{color:var(--muted);font-size:11.5px}
.counts{display:flex;gap:20px;flex-wrap:wrap;margin-bottom:14px;font-family:var(--mono);font-size:13px}
@@ -287,15 +289,16 @@ async function runPreview(){
previewRows = j.rows || [];
renderPreview(j);
const note = j.enriched ? 'проверено против mailcow (домены + дубликаты + квоты)' : (j.enrichNote||'');
setStatus($('#previewStatus'), j.enriched?'ok':'info', (j.enriched?'● ':'')+ 'строк: '+j.total+' · '+note);
const fmt = j.format === 'kerio' ? 'формат: экспорт Kerio (логин ← Name, пароль ← Description) · ' : '';
setStatus($('#previewStatus'), j.enriched?'ok':'info', (j.enriched?'● ':'')+ 'строк: '+j.total+' · '+fmt+note);
}catch(e){ setStatus($('#previewStatus'),'err','ошибка: '+e.message); }
b.disabled = false;
}
function renderPreview(j){
const s = j.summary||{};
const labels = {create:'к созданию', warn:'с предупреждением', exists:'уже есть', error:'ошибки'};
$('#summary').innerHTML = ['create','warn','exists','error'].map(k=>
const labels = {create:'к созданию', warn:'с предупреждением', exists:'уже есть', skip:'служебные', error:'ошибки'};
$('#summary').innerHTML = ['create','warn','exists','skip','error'].map(k=>
`<span class="pill ${k}"><span class="c"></span>${labels[k]}: ${s[k]||0}</span>`).join('');
const body = $('#prevBody'); body.innerHTML='';
previewRows.forEach(r=>{
@@ -335,12 +338,12 @@ function renderPreview(j){
$('#importHint').textContent = blocked
? 'создание заблокировано — сначала увеличьте квоту домена (см. предупреждение выше)'
: importable
? `будет создано ${importable} ящик(ов); строки "уже есть"/"ошибки" пропускаются`
? `будет создано ${importable} ящик(ов); строки "уже есть"/"служебная"/"ошибки" пропускаются`
: 'нет строк, пригодных к созданию';
$('#btnImport').textContent = importable ? `Создать ${importable} ящик(ов)` : 'Создать ящики';
}
const gb = mib => mib >= 1024 ? (mib/1024).toFixed(mib%1024?1:0)+' ГБ' : mib+' МиБ';
const statusText = s => ({create:'создать',warn:'создать (!)',exists:'пропуск',error:'ошибка'}[s]||s);
const statusText = s => ({create:'создать',warn:'создать (!)',exists:'пропуск',skip:'служебная',error:'ошибка'}[s]||s);
const esc = s => String(s==null?'':s).replace(/[&<>]/g,c=>({'&':'&amp;','<':'&lt;','>':'&gt;'}[c]));
// --- 03 import (streamed NDJSON) ---