(function () { "use strict"; const REG = [ { num: "7271UV", type: "SIP", station: "ГТС Алматы", city: "Алматы", desc: "Оконечный номер экстренных служб (пример схемы)", reserve: "Есть: SIP Trunk 7272222222 (принадлежит ГТС Алматы)", }, { num: "727103", type: "BRW SIP", station: "ГТС Алматы", city: "Алматы", desc: "Номер пересчёта принадлежит BRW SIP 7273130333", reserve: "Есть: SIP Trunk 7272222222 (принадлежит ГТС Алматы)", }, { num: "7272222222", type: "ТДМ", station: "ГТС Алматы", city: "Алматы", desc: "Резервный номер в SIP Trunk, принадлежит ГТС Алматы", reserve: "Резерв для 7271UV", }, ]; const OWNERS = [ { name: "ГТС Алматы (собственный номер станции)", short: "ГТС Алматы", match: function (d) { return d.owner === "own"; } }, { name: "BRW SIP", short: "BRW SIP", match: function (d) { return d.owner === "brw-sip"; } }, { name: "АТС", short: "АТС", match: function (d) { return d.owner === "pbx"; } }, { name: "АТС зоны", short: "АТС зоны", match: function (d) { return d.owner === "zone"; } }, ]; function normalize(v) { return String(v == null ? "" : v).replace(/\s+/g, "").toUpperCase(); } function findEntry(num) { const n = normalize(num); if (!n) return null; return REG.find(function (e) { return normalize(e.num) === n; }) || null; } function derive(raw) { let n = normalize(raw); n = n.replace(/^(?:[8]\+?7|0)/, ""); if (!/^[0-9A-Z]+$/.test(n)) return null; const digits = n.replace(/[^0-9]/g, ""); const city = digits.startsWith("727") ? "Алматы" : "неизвестен"; const entry = findEntry(raw); let owner, reserve, viaStation, isReserve = false; if (entry) { owner = ownerByType(entry.type); reserve = entry.reserve; viaStation = entry.station; isReserve = /резерв/i.test(entry.desc); } else { owner = digits.length >= 8 ? "pbx" : "zone"; reserve = "Не определён (номер не в реестре)"; viaStation = "неизвестна"; } const owners = OWNERS.filter(function (o) { return o.match({ owner: owner }); }); const ownerName = owners.length ? owners[0].name : "станция-владелец"; const endLabel = entry ? "Оконечный номер " + entry.num : "Оконечный номер"; const mobile = [ { t: "Мобильный оператор" }, { t: "SSW/NGN транзит" }, { t: "SSW/NGN рег." }, { t: endLabel, active: true }, ]; const fixed = [ { t: "Станция владельца номера абонента" }, { t: "SSW/NGN рег." + (viaStation ? " (" + viaStation + ")" : "") }, { t: endLabel, active: true }, ]; if (owner === "brw-sip") { fixed.splice(2, 0, { t: "Номер пересчёта → BRW SIP", active: true }); } if (reserve && !/не определён/i.test(reserve) && !isReserve) { const rnum = reserve.replace(/^Есть[:\s]*/, "").split(/[\s(]/)[0]; mobile.push({ t: "Резерв", sub: rnum + " · авт. при недоступности SIP" }); fixed.push({ t: "Резерв", sub: rnum + " · авт. при недоступности SIP" }); } return { entry: entry, city: city, owner: owner, ownerName: ownerName, reserve: reserve, viaStation: viaStation, mobile: mobile, fixed: fixed }; } function ownerByType(type) { const t = normalize(type); if (t.indexOf("BRW") === 0) return "brw-sip"; if (t === "SIP" || t === "GPON") return "pbx"; if (t === "ТДМ") return "own"; return "zone"; } function renderChain(id, nodes) { const el = document.getElementById(id); el.innerHTML = ""; nodes.forEach(function (node, i) { const d = document.createElement("div"); d.className = "chain-node" + (node.active ? " active" : ""); const s = document.createElement("strong"); s.textContent = node.t; d.appendChild(s); if (node.sub) { const sp = document.createElement("span"); sp.textContent = node.sub; d.appendChild(sp); } el.appendChild(d); if (i < nodes.length - 1) { const a = document.createElement("span"); a.className = "chain-arrow"; a.setAttribute("aria-hidden", "true"); a.innerHTML = "→"; el.appendChild(a); } }); } function chip(text, tone) { const s = document.createElement("span"); s.className = "kt-ai-chip"; if (tone) s.setAttribute("data-tone", tone); s.textContent = text; return s; } function show(num) { const d = derive(num); const detail = document.getElementById("resDetail"); if (!d) { detail.style.display = "none"; const empty = '
Проверьте номерВведите ABC21UV
'; document.getElementById("chain1").innerHTML = empty; document.getElementById("chain2").innerHTML = empty; document.getElementById("r1src").textContent = ""; document.getElementById("r2src").textContent = ""; return; } detail.style.display = "block"; document.getElementById("rdNum").textContent = d.entry ? d.entry.num : num.trim().toUpperCase(); const chips = document.getElementById("rdChips"); chips.innerHTML = ""; if (d.entry) { chips.appendChild(chip(d.entry.type, "blue")); chips.appendChild(chip(d.entry.station, "gray")); chips.appendChild(chip("Город: " + d.entry.city, "gray")); } else { chips.appendChild(chip("Город: " + d.city, "gray")); } document.getElementById("rdMeta").textContent = d.entry ? d.entry.desc : "Номер не найден в реестре — показан базовый маршрут."; document.getElementById("rdOwn").textContent = "Владелец (по пересчёту): " + d.ownerName; const r = document.getElementById("rdReserve"); if (/не определён/i.test(d.reserve)) { r.style.display = "none"; } else { r.style.display = "block"; r.textContent = "Резерв: " + d.reserve; } document.getElementById("r1src").textContent = "Мобильный оператор → SSW/NGN транзит → SSW/NGN рег. → " + (d.entry ? d.entry.num : "оконечный номер"); document.getElementById("r2src").textContent = "Станция владельца номера → SSW/NGN рег. → " + (d.entry ? d.entry.num : "оконечный номер"); renderChain("chain1", d.mobile); renderChain("chain2", d.fixed); renderScheme(d.entry ? d.entry.num : num); } function renderRegister() { const list = document.getElementById("regList"); list.innerHTML = ""; REG.forEach(function (e) { const row = document.createElement("div"); row.className = "kt-ai-card reg-row"; const top = document.createElement("div"); top.className = "reg-row-top"; const num = document.createElement("span"); num.className = "reg-row-num"; num.textContent = e.num; top.appendChild(num); top.appendChild(chip(e.type, "blue")); top.appendChild(chip(e.station, "gray")); top.appendChild(chip("Резерв: есть", "green")); row.appendChild(top); const meta = document.createElement("div"); meta.className = "reg-row-meta"; meta.textContent = e.desc + " · Город: " + e.city + " · Формат набора: ABC21UV"; row.appendChild(meta); const res = document.createElement("div"); res.className = "reg-row-reserve"; res.textContent = "Резерв: " + e.reserve; row.appendChild(res); list.appendChild(row); }); document.getElementById("regCounter").textContent = "Каждый номер: тип (ТДМ / GPON / SIP), станция владения, формат набора ABC21UV и резерв. В реестре: " + REG.length + "."; } function renderScheme(focusNum) { const NS = "http://www.w3.org/2000/svg"; const svg = document.createElementNS(NS, "svg"); svg.setAttribute("viewBox", "0 0 1100 460"); svg.setAttribute("role", "img"); svg.setAttribute("aria-label", "Схема маршрутизации вызовов экстренных служб"); const entry = findEntry(focusNum) || REG[0] || null; const endNum = entry ? entry.num : "—"; const hasBrw = entry ? normalize(entry.type).indexOf("BRW") === 0 : false; function rect(x, y, w, h, rx, fill, stroke, sw) { const r = document.createElementNS(NS, "rect"); r.setAttribute("x", x); r.setAttribute("y", y); r.setAttribute("width", w); r.setAttribute("height", h); r.setAttribute("rx", rx); if (fill) r.setAttribute("fill", fill); if (stroke) r.setAttribute("stroke", stroke); r.setAttribute("stroke-width", sw || 1); return r; } function txt(x, y, s, size, fill, weight) { const t = document.createElementNS(NS, "text"); t.setAttribute("x", x); t.setAttribute("y", y); t.setAttribute("text-anchor", "middle"); t.setAttribute("style", "font-size:" + size + "px; fill:" + fill + ";" + (weight ? " font-weight:" + weight + ";" : "")); t.textContent = s; return t; } function edge(x1, y1, x2, y2, dashed, label, ldy) { const l = document.createElementNS(NS, "line"); l.setAttribute("x1", x1); l.setAttribute("y1", y1); l.setAttribute("x2", x2); l.setAttribute("y2", y2); l.setAttribute("stroke", dashed ? "var(--kt-ai-fg-muted)" : "var(--vibe-accent)"); l.setAttribute("stroke-width", "1.6"); if (dashed) l.setAttribute("stroke-dasharray", "5 4"); l.setAttribute("marker-end", "url(#arrow" + (dashed ? "M" : "A") + ")"); l.setAttribute("opacity", "0.85"); svg.appendChild(l); if (label) { const t = document.createElementNS(NS, "text"); t.setAttribute("x", (x1 + x2) / 2); t.setAttribute("y", ((y1 + y2) / 2) + (ldy || -7)); t.setAttribute("text-anchor", "middle"); t.setAttribute("style", "font-size:10px; fill:var(--kt-ai-fg-muted)"); t.textContent = label; svg.appendChild(t); } } const defs = document.createElementNS(NS, "defs"); defs.innerHTML = ''; svg.appendChild(defs); edge(215, 60, 390, 170); edge(385, 60, 530, 170); edge(560, 204, 620, 266); if (hasBrw) { edge(695, 300, 656, 334); } edge(620, 300, 350, 335, true, "резерв при недоступности SIP", -7); const boxFill = "var(--kt-ai-card-bg)"; const bStroke = "var(--kt-ai-border)"; // Мобильные операторы svg.appendChild(rect(50, 32, 165, 56, 10, boxFill, bStroke)); svg.appendChild(txt(132, 56, "Мобильные", 14, "var(--kt-ai-fg)", 600)); svg.appendChild(txt(132, 73, "операторы", 14, "var(--kt-ai-fg)", 600)); // ГТС svg.appendChild(rect(220, 32, 165, 56, 10, boxFill, bStroke)); svg.appendChild(txt(302, 63, "ГТС", 15, "var(--kt-ai-fg)", 600)); // SSW/NGN транзит svg.appendChild(rect(390, 170, 170, 56, 10, boxFill, bStroke)); svg.appendChild(txt(475, 193, "SSW/NGN транзит", 14, "var(--kt-ai-fg)", 600)); svg.appendChild(txt(475, 210, "транзитная шлюзовая система", 11, "var(--kt-ai-fg-muted)")); // SSW/NGN рег. svg.appendChild(rect(550, 266, 170, 56, 10, boxFill, bStroke)); svg.appendChild(txt(635, 289, "SSW/NGN рег.", 14, "var(--kt-ai-fg)", 600)); svg.appendChild(txt(635, 306, "региональная маршрутизация", 11, "var(--kt-ai-fg-muted)")); // Резерв svg.appendChild(rect(200, 335, 150, 56, 10, "var(--kt-ai-bg)", bStroke)); svg.appendChild(txt(275, 358, "SIP Trunk (резерв)", 12, "var(--kt-ai-fg)", 600)); svg.appendChild(txt(275, 375, "7272222222 · ГТС Алматы", 11, "var(--kt-ai-fg-muted)")); // Оконечный номер svg.appendChild(rect(700, 335, 190, 56, 10, "var(--kt-ai-bg)", hasBrw ? "var(--vibe-accent)" : bStroke, hasBrw ? 2 : 1)); svg.appendChild(txt(795, 358, "Оконечный номер", 13, "var(--kt-ai-fg)", 600)); svg.appendChild(txt(795, 375, endNum, 12, "var(--vibe-accent)", 600)); // BRW SIP if (hasBrw) { svg.appendChild(rect(450, 335, 205, 56, 10, boxFill, bStroke)); svg.appendChild(txt(552, 358, "BRW SIP", 14, "var(--kt-ai-fg)", 600)); svg.appendChild(txt(552, 375, "7273130333", 12, "var(--kt-ai-fg-muted)", 600)); const l1 = document.createElementNS(NS, "line"); l1.setAttribute("x1", 655); l1.setAttribute("y1", 363); l1.setAttribute("x2", 695); l1.setAttribute("y2", 363); l1.setAttribute("stroke", "var(--vibe-accent)"); l1.setAttribute("stroke-width", "1.6"); l1.setAttribute("marker-end", "url(#arrowA)"); l1.setAttribute("opacity", "0.85"); svg.appendChild(l1); } const el = document.getElementById("schemeSvg"); el.innerHTML = ""; el.appendChild(svg); } document.addEventListener("DOMContentLoaded", function () { renderRegister(); renderScheme("727103"); const input = document.getElementById("num"); const btn = document.getElementById("findBtn"); btn.addEventListener("click", function () { show(input.value); }); input.addEventListener("keydown", function (ev) { if (ev.key === "Enter") show(input.value); }); input.addEventListener("input", function () { show(input.value); }); show("7271UV"); }); })();