(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");
});
})();