146 lines
6.3 KiB
HTML
146 lines
6.3 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="ru">
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||
<title>Interface Parser — JunOS</title>
|
||
<style>
|
||
*{box-sizing:border-box;margin:0;padding:0}
|
||
body{font:15px/1.5 -apple-system,BlinkMacSystemFont,"Segoe UI",Inter,system-ui,sans-serif;background:#f0f2f5;color:#0F1218;padding:32px 24px}
|
||
.container{max-width:1100px;margin:0 auto}
|
||
h1{font-size:28px;font-weight:800;margin-bottom:4px}
|
||
.sub{color:#5B6573;font-size:15px;margin-bottom:28px}
|
||
.layout{display:grid;grid-template-columns:1fr 1fr;gap:24px}
|
||
.panel{background:#fff;border-radius:16px;padding:24px;box-shadow:0 2px 12px rgba(0,0,0,.04)}
|
||
.panel h2{font-size:17px;font-weight:700;margin-bottom:12px}
|
||
textarea{width:100%;height:400px;padding:14px;border:2px solid #d0d5dd;border-radius:10px;font:13px/1.5 "SF Mono","Fira Code","Courier New",monospace;resize:vertical;outline:none;transition:.15s}
|
||
textarea:focus{border-color:#0F1218}
|
||
button{padding:12px 28px;background:#0F1218;color:#fff;border:none;border-radius:10px;font-size:15px;font-weight:700;cursor:pointer;margin-top:12px;transition:.15s}
|
||
button:hover{background:#2a2f3a}
|
||
.stats{margin-top:12px;display:flex;gap:16px;flex-wrap:wrap}
|
||
.stat{font-size:13px;color:#5B6573;background:#f6f8fa;padding:6px 14px;border-radius:6px}
|
||
table{width:100%;border-collapse:collapse;font-size:13px}
|
||
thead th{background:#f6f8fa;padding:10px 12px;text-align:left;font-weight:600;font-size:12px;color:#5B6573;border-bottom:2px solid #e8eaed;position:sticky;top:0}
|
||
tbody td{padding:10px 12px;border-bottom:1px solid #f0f2f5;vertical-align:top}
|
||
tbody tr:hover{background:#f8faff}
|
||
tr.disabled td{opacity:.5}
|
||
.intf{font-weight:600;font-family:monospace;white-space:nowrap}
|
||
.desc{color:#0F1218;max-width:260px;word-break:break-all}
|
||
.status{display:inline-block;padding:2px 10px;border-radius:12px;font-size:11px;font-weight:600}
|
||
.status.off{background:#fee8e8;color:#c0392b}
|
||
.status.on{background:#e8f8e8;color:#27ae60}
|
||
.mode{font-family:monospace;font-size:12px;padding:2px 8px;border-radius:4px;background:#f0f2f5}
|
||
.portmap{font-size:12px;color:#5B6573;font-family:monospace}
|
||
.empty{text-align:center;padding:60px 20px;color:#9aa3b2}
|
||
.empty p{font-size:15px;margin-top:8px}
|
||
@media(max-width:768px){.layout{grid-template-columns:1fr}.panel{padding:16px}textarea{height:250px}}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="container">
|
||
<h1>🔌 Interface Parser — JunOS</h1>
|
||
<p class="sub">Вставь конфиг JunOS — получи таблицу интерфейсов</p>
|
||
|
||
<div class="layout">
|
||
<div class="panel">
|
||
<h2>📄 Конфиг</h2>
|
||
<textarea id="configInput" placeholder='Вставь сюда вывод "show configuration interfaces" или set-команды... Пример: set interfaces ge-0/0/1 description Kazteleport/8117714/12mb set interfaces ge-0/0/1 disable set interfaces ge-0/0/1 unit 0 family ethernet-switching port-mode access set interfaces ge-0/0/1 unit 0 family ethernet-switching vlan members vlan1793 set interfaces ge-0/0/2 unit 0 family ethernet-switching port-mode access'></textarea>
|
||
<button onclick="parse()">Разобрать конфиг</button>
|
||
<div class="stats" id="stats"></div>
|
||
</div>
|
||
|
||
<div class="panel">
|
||
<h2>📊 Интерфейсы</h2>
|
||
<div id="result"><div class="empty"><div style="font-size:48px">📋</div><p>Вставь конфиг слева и нажми «Разобрать»</p></div></div>
|
||
<div id="portmap"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<script>
|
||
const PORTS_PER = 16;
|
||
const TOTAL = 84;
|
||
|
||
function parse(){
|
||
const text=document.getElementById('configInput').value;
|
||
const stats=document.getElementById('stats');
|
||
const result=document.getElementById('result');
|
||
const portmap=document.getElementById('portmap');
|
||
|
||
const lines=text.split('\n').map(l=>l.trim()).filter(l=>l&&l.startsWith('set interfaces'));
|
||
if(!lines.length){
|
||
result.innerHTML='<div class="empty"><div style="font-size:48px">⚠️</div><p>Ничего не найдено. Вставь строки начинающиеся с set interfaces</p></div>';
|
||
stats.innerHTML='';
|
||
portmap.innerHTML='';
|
||
return;
|
||
}
|
||
|
||
const ifaces={};
|
||
const order=[];
|
||
|
||
lines.forEach(line=>{
|
||
// Parse: set interfaces ge-0/0/X ...
|
||
const match=line.match(/set interfaces (ge-\d+\/\d+\/\d+)/);
|
||
if(!match)return;
|
||
const name=match[1];
|
||
if(!ifaces[name]){
|
||
ifaces[name]={name,descr:'',disabled:false,mode:'',vlan:''};
|
||
order.push(name);
|
||
}
|
||
const iface=ifaces[name];
|
||
|
||
if(/ description /.test(line)){
|
||
const d=line.match(/description (.+)$/);
|
||
if(d)iface.descr=d[1];
|
||
}
|
||
if(/ disable$/.test(line)){
|
||
iface.disabled=true;
|
||
}
|
||
if(/ no-traps/.test(line)){
|
||
// no change to status
|
||
}
|
||
if(/ port-mode /.test(line)){
|
||
const m=line.match(/port-mode (\w+)/);
|
||
if(m)iface.mode=m[1];
|
||
}
|
||
if(/ vlan members /.test(line)){
|
||
const v=line.match(/vlan members (\S+)/);
|
||
if(v)iface.vlan=v[1];
|
||
}
|
||
});
|
||
|
||
stats.innerHTML=`
|
||
<span class="stat">📡 ${order.length} интерфейсов</span>
|
||
<span class="stat">🔴 ${order.filter(n=>ifaces[n].disabled).length} disabled</span>
|
||
<span class="stat">🟢 ${order.filter(n=>!ifaces[n].disabled).length} active</span>
|
||
`;
|
||
|
||
if(!order.length){
|
||
result.innerHTML='<div class="empty"><div style="font-size:48px">⚠️</div><p>Не удалось распознать интерфейсы. Проверь формат.</p></div>';
|
||
portmap.innerHTML='';
|
||
return;
|
||
}
|
||
|
||
let table='<table><thead><tr><th>Интерфейс</th><th>Описание</th><th>Статус</th><th>Режим</th><th>VLAN</th></tr></thead><tbody>';
|
||
order.forEach(name=>{
|
||
const i=ifaces[name];
|
||
table+=`<tr class="${i.disabled?'disabled':''}">
|
||
<td class="intf">${name}</td>
|
||
<td class="desc">${i.descr||'—'}</td>
|
||
<td><span class="status ${i.disabled?'off':'on'}">${i.disabled?'off':'on'}</span></td>
|
||
<td>${i.mode?`<span class="mode">${i.mode}</span>`:'—'}</td>
|
||
<td>${i.vlan||'—'}</td>
|
||
</tr>`;
|
||
});
|
||
table+='</tbody></table>';
|
||
result.innerHTML=table;
|
||
|
||
// cassette/port mapping for first 16 intfs
|
||
portmap.innerHTML='';
|
||
}
|
||
|
||
document.getElementById('configInput').addEventListener('keydown',e=>{if((e.ctrlKey||e.metaKey)&&e.key==='Enter')parse()});
|
||
</script>
|
||
</body>
|
||
</html>
|