dashbord-roznichnyh-prodazh-3/script.js

485 lines
22 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use strict";
// ---------- Данные: розничные продажи по городам (февраль 2026) ----------
// revenue/ttraffic — февраль в миллионах тенге; jan — январь (для динамики);
// trend — выручка за 6 месяцев; share — доля розницы в выручке города, %;
// directions — направления продаж; channels — выручка по каналам, млн ₸.
var CITIES = [
{
id: "almaty", name: "Алматы",
revenue: 148.5, traffic: 21.3, avgCheck: 6972, stores: 21,
jan: 132.0, share: 34,
status: "ok", statusText: "Выше плана",
directions: [
{ id: "inet", name: "Интернет", revenue: 38.4, jan: 36.1, trend: [33.1, 33.8, 35.0, 34.2, 35.6, 38.4], shareOfCity: 26, channels: [27.9, 7.7, 2.8] },
{ id: "tv", name: "Телевидение", revenue: 29.1, jan: 26.4, trend: [24.0, 25.1, 26.0, 25.5, 27.2, 29.1], shareOfCity: 20, channels: [18.6, 7.5, 3.0] },
{ id: "mobile", name: "Мобильная связь", revenue: 46.2, jan: 43.8, trend: [40.5, 41.2, 43.0, 42.1, 44.5, 46.2], shareOfCity: 31, channels: [33.7, 9.5, 3.0] },
{ id: "smart", name: "Умный дом", revenue: 22.7, jan: 17.6, trend: [15.2, 15.9, 17.0, 16.8, 20.1, 22.7], shareOfCity: 15, channels: [16.0, 4.5, 2.2] },
{ id: "b2b", name: "Корпоративные решения", revenue: 12.1, jan: 10.2, trend: [8.8, 9.1, 10.0, 9.6, 11.0, 12.1], shareOfCity: 8, channels: [9.1, 2.4, 0.6] }
],
channels: [91.3, 26.4, 10.8]
},
{
id: "astana", name: "Астана",
revenue: 131.7, traffic: 18.6, avgCheck: 7081, stores: 17,
jan: 119.5, share: 31,
status: "ok", statusText: "Выше плана",
directions: [
{ id: "inet", name: "Интернет", revenue: 35.2, jan: 31.9, trend: [28.5, 29.4, 31.0, 30.2, 33.0, 35.2], shareOfCity: 27, channels: [24.6, 7.2, 3.4] },
{ id: "tv", name: "Телевидение", revenue: 28.4, jan: 25.8, trend: [23.5, 24.2, 25.5, 24.9, 27.0, 28.4], shareOfCity: 22, channels: [18.2, 7.0, 3.2] },
{ id: "mobile", name: "Мобильная связь", revenue: 40.3, jan: 38.6, trend: [35.5, 36.1, 38.0, 37.2, 39.0, 40.3], shareOfCity: 31, channels: [28.2, 8.5, 3.6] },
{ id: "smart", name: "Умный дом", revenue: 18.9, jan: 15.3, trend: [12.8, 13.4, 14.6, 14.2, 17.0, 18.9], shareOfCity: 14, channels: [13.2, 3.9, 1.8] },
{ id: "b2b", name: "Корпоративные решения", revenue: 8.9, jan: 10.7, trend: [11.0, 10.8, 9.9, 9.6, 9.2, 8.9], shareOfCity: 7, channels: [6.7, 1.8, 0.4] }
],
channels: [81.3, 23.4, 11.0]
},
{
id: "shymkent", name: "Шымкент",
revenue: 79.6, traffic: 13.2, avgCheck: 6030, stores: 10,
jan: 71.4, share: 28,
status: "warn", statusText: "Растёт",
directions: [
{ id: "tv", name: "Телевидение", revenue: 30.5, jan: 27.9, trend: [25.0, 26.0, 27.0, 26.5, 29.0, 30.5], shareOfCity: 38, channels: [19.8, 6.9, 3.8] },
{ id: "inet", name: "Интернет", revenue: 22.1, jan: 19.8, trend: [16.4, 17.1, 18.3, 17.8, 19.5, 22.1], shareOfCity: 28, channels: [14.4, 5.1, 2.6] },
{ id: "mobile", name: "Мобильная связь", revenue: 15.8, jan: 15.1, trend: [13.9, 14.2, 14.8, 14.5, 15.2, 15.8], shareOfCity: 20, channels: [11.1, 3.2, 1.5] },
{ id: "smart", name: "Умный дом", revenue: 11.2, jan: 8.6, trend: [6.4, 6.8, 7.5, 7.2, 9.8, 11.2], shareOfCity: 14, channels: [7.8, 2.4, 1.0] }
],
channels: [53.1, 17.6, 8.9]
},
{
id: "karaganda", name: "Караганда",
revenue: 56.4, traffic: 9.4, avgCheck: 5999, stores: 8,
jan: 53.2, share: 26,
status: "ok", statusText: "Выше плана",
directions: [
{ id: "tv", name: "Телевидение", revenue: 22.4, jan: 21.1, trend: [18.5, 19.0, 20.0, 19.6, 21.0, 22.4], shareOfCity: 40, channels: [14.6, 5.0, 2.8] },
{ id: "inet", name: "Интернет", revenue: 17.6, jan: 16.5, trend: [14.0, 14.6, 15.4, 15.0, 16.4, 17.6], shareOfCity: 31, channels: [11.4, 4.2, 2.0] },
{ id: "mobile", name: "Мобильная связь", revenue: 10.3, jan: 9.7, trend: [8.7, 9.0, 9.4, 9.2, 9.8, 10.3], shareOfCity: 18, channels: [7.2, 2.2, 0.9] },
{ id: "smart", name: "Умный дом", revenue: 6.1, jan: 5.9, trend: [4.6, 4.9, 5.3, 5.1, 5.6, 6.1], shareOfCity: 11, channels: [4.3, 1.3, 0.5] }
],
channels: [37.5, 12.7, 6.2]
},
{
id: "aktobe", name: "Актобе",
revenue: 47.8, traffic: 7.9, avgCheck: 6051, stores: 7,
jan: 42.1, share: 25,
status: "ok", statusText: "Выше плана",
directions: [
{ id: "inet", name: "Интернет", revenue: 15.9, jan: 14.3, trend: [11.8, 12.3, 13.2, 12.8, 14.1, 15.9], shareOfCity: 33, channels: [10.1, 4.0, 1.8] },
{ id: "tv", name: "Телевидение", revenue: 14.8, jan: 13.9, trend: [12.0, 12.5, 13.2, 12.9, 14.0, 14.8], shareOfCity: 31, channels: [9.5, 3.6, 1.7] },
{ id: "mobile", name: "Мобильная связь", revenue: 9.7, jan: 8.8, trend: [7.6, 8.0, 8.4, 8.2, 9.0, 9.7], shareOfCity: 20, channels: [6.8, 2.1, 0.8] },
{ id: "smart", name: "Умный дом", revenue: 7.4, jan: 5.1, trend: [3.8, 4.1, 4.4, 4.2, 6.1, 7.4], shareOfCity: 16, channels: [5.1, 1.6, 0.7] }
],
channels: [31.5, 11.3, 5.0]
},
{
id: "petropavl", name: "Петропавловск",
revenue: 38.9, traffic: 6.2, avgCheck: 6274, stores: 5,
jan: 33.4, share: 24,
status: "ok", statusText: "Выше плана",
directions: [
{ id: "tv", name: "Телевидение", revenue: 16.2, jan: 14.6, trend: [12.4, 12.9, 13.6, 13.2, 15.0, 16.2], shareOfCity: 42, channels: [10.0, 3.9, 2.3] },
{ id: "inet", name: "Интернет", revenue: 12.4, jan: 11.2, trend: [9.2, 9.6, 10.3, 9.9, 11.0, 12.4], shareOfCity: 32, channels: [7.6, 3.1, 1.7] },
{ id: "mobile", name: "Мобильная связь", revenue: 7.1, jan: 6.5, trend: [5.5, 5.7, 6.1, 5.9, 6.6, 7.1], shareOfCity: 18, channels: [4.9, 1.6, 0.6] },
{ id: "smart", name: "Умный дом", revenue: 3.2, jan: 1.1, trend: [0.7, 0.8, 0.9, 0.8, 1.9, 3.2], shareOfCity: 8, channels: [2.0, 0.8, 0.4] }
],
channels: [24.5, 9.4, 5.0]
},
{
id: "kostanay", name: "Костанай",
revenue: 33.2, traffic: 5.3, avgCheck: 6264, stores: 4,
jan: 31.7, share: 23,
status: "warn", statusText: "Растёт",
directions: [
{ id: "tv", name: "Телевидение", revenue: 14.1, jan: 13.5, trend: [11.6, 12.0, 12.7, 12.4, 13.3, 14.1], shareOfCity: 42, channels: [8.9, 3.4, 1.8] },
{ id: "inet", name: "Интернет", revenue: 10.8, jan: 10.2, trend: [8.5, 8.8, 9.4, 9.1, 10.0, 10.8], shareOfCity: 33, channels: [6.8, 2.7, 1.3] },
{ id: "mobile", name: "Мобильная связь", revenue: 6.6, jan: 6.3, trend: [5.2, 5.4, 5.7, 5.5, 6.1, 6.6], shareOfCity: 20, channels: [4.6, 1.5, 0.5] },
{ id: "smart", name: "Умный дом", revenue: 1.7, jan: 0.7, trend: [0.5, 0.5, 0.6, 0.6, 1.2, 1.7], shareOfCity: 5, channels: [1.1, 0.4, 0.2] }
],
channels: [21.4, 8.0, 3.8]
},
{
id: "taraz", name: "Тараз",
revenue: 28.6, traffic: 4.6, avgCheck: 6217, stores: 4,
jan: 32.1, share: 22,
status: "risk", statusText: "Ниже плана",
directions: [
{ id: "tv", name: "Телевидение", revenue: 12.3, jan: 13.2, trend: [13.5, 13.3, 13.0, 12.8, 12.5, 12.3], shareOfCity: 43, channels: [7.7, 3.0, 1.6] },
{ id: "inet", name: "Интернет", revenue: 9.4, jan: 10.1, trend: [10.6, 10.3, 9.9, 9.7, 9.6, 9.4], shareOfCity: 33, channels: [5.9, 2.3, 1.2] },
{ id: "mobile", name: "Мобильная связь", revenue: 5.4, jan: 5.8, trend: [6.0, 5.9, 5.7, 5.6, 5.5, 5.4], shareOfCity: 19, channels: [3.8, 1.2, 0.4] },
{ id: "smart", name: "Умный дом", revenue: 1.5, jan: 3.0, trend: [3.2, 3.0, 2.6, 2.2, 1.8, 1.5], shareOfCity: 5, channels: [1.0, 0.4, 0.1] }
],
channels: [18.4, 6.9, 3.3]
}
];
var MONTHS = ["сент 2025", "окт 2025", "нояб 2025", "дек 2025", "янв 2026", "фев 2026"];
var MONTHS_SHORT = ["С", "О", "Н", "Д", "Я", "Ф"];
var CHANNEL_NAMES = ["Магазины", "Колл-центр", "Онлайн"];
var DIR_LABELS = { inet: "Интернет", tv: "Телевидение", mobile: "Мобильная связь", smart: "Умный дом", b2b: "Корпоратив" };
var state = { search: "", dir: "", city: null };
// ---------- Форматирование ----------
function fmtNum(n, digits) {
var s = (n == null) ? "—" : Number(n).toFixed(digits == null ? 1 : digits);
return s.replace(".", ",").replace(/\B(?=(\d{3})+(?!\d))/g, " ");
}
function fmtInt(n) {
return String(n).replace(/\B(?=(\d{3})+(?!\d))/g, " ");
}
function fmtM(mn) { return fmtNum(mn, 1) + " млн ₸"; }
function deltaPct(cur, prev) {
if (!prev) return 0;
return ((cur - prev) / prev) * 100;
}
// ---------- Расчёты агрегатов ----------
// Суммарная выручка с учётом фильтра направлений:
// если направление выбрано — только его строки, иначе все направления города.
function cityRevenue(c) {
if (!state.dir) return c.revenue;
for (var i = 0; i < c.directions.length; i++) {
if (c.directions[i].id === state.dir) return c.directions[i].revenue;
if (DIR_LABELS[c.directions[i].id] === state.dir) return c.directions[i].revenue;
}
return 0;
}
function cityJan(c) {
if (!state.dir) return c.jan;
for (var i = 0; i < c.directions.length; i++) {
var d = c.directions[i];
if (d.id === state.dir || DIR_LABELS[d.id] === state.dir) return d.jan;
}
return 0;
}
function cityTraffic(c) {
if (!state.dir || state.dir === "tv" || state.dir === "Телевидение") return c.traffic;
return Math.round(c.traffic * 0.12 * 10) / 10;
}
function cityStores(c) {
if (!state.dir) return c.stores;
var map = { inet: 0.30, tv: 0.25, mobile: 0.20, smart: 0.15, b2b: 0.10 };
var f = 0.25;
for (var k in map) if (k === state.dir) f = map[k];
return Math.max(1, Math.round(c.stores * f));
}
function dirMatches(c, dir) {
if (!dir) return true;
for (var i = 0; i < c.directions.length; i++) {
if (c.directions[i].id === dir || DIR_LABELS[c.directions[i].id] === dir) return true;
}
return false;
}
function visibleCities() {
var q = state.search.toLowerCase();
var out = [];
for (var i = 0; i < CITIES.length; i++) {
var c = CITIES[i];
if (q && c.name.toLowerCase().indexOf(q) === -1) continue;
if (state.dir && !dirMatches(c, state.dir)) continue;
out.push(c);
}
return out;
}
function totals(cities) {
var rev = 0, jan = 0, traffic = 0, stores = 0, n = cities.length;
for (var i = 0; i < cities.length; i++) {
rev += cityRevenue(cities[i]);
jan += cityJan(cities[i]);
traffic += cityTraffic(cities[i]);
stores += cityStores(cities[i]);
}
var check = (rev * 100) / (traffic || 1);
return { rev: rev, jan: jan, traffic: traffic, avgCheck: check, stores: stores, n: n, delta: deltaPct(rev, jan) };
}
// ---------- Рендер: главный экран ----------
var ARROW_UP = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M7 17 17 7M8 7h9v9"/></svg>';
var ARROW_DOWN = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M7 7 17 17M17 8v9H8"/></svg>';
function kpiCard(label, value, hint) {
return '<div class="kt-ai-kpi">' +
'<div class="label">' + label + '</div>' +
'<div class="value">' + value + '</div>' +
(hint ? '<div class="hint">' + hint + '</div>' : '') +
'</div>';
}
function deltaCell(delta) {
var dir = delta >= 0 ? "up" : "down";
var arrow = delta >= 0 ? ARROW_UP : ARROW_DOWN;
return '<span class="delta" data-dir="' + dir + '">' + arrow + (delta >= 0 ? "+" : "") + fmtNum(delta, 1) + " %</span>";
}
function statusPill(status, text) {
return '<span class="kt-ai-status-pill" data-status="' + status + '">' + text + '</span>';
}
function renderKpis() {
var t = totals(visibleCities());
var dirName = state.dir || "все направления";
var html = "";
html += kpiCard("Выручка за февраль", fmtNum(t.rev, 1) + " млн ₸", "к январю: " + (t.delta >= 0 ? "+" : "") + fmtNum(t.delta, 1) + " %");
html += kpiCard("Средний чек", fmtInt(Math.round(t.avgCheck)) + " ₸", "февраль 2026");
html += kpiCard("Трафик", fmtInt(Math.round(t.traffic * 1000)) + " визитов", "во всех магазинах сети");
html += kpiCard("Магазины", String(t.stores), "в " + t.n + " городах · " + dirName);
var el = $("kpiMain");
if (el) el.innerHTML = html;
}
function renderTop() {
var list = visibleCities().slice().sort(function (a, b) { return cityRevenue(b) - cityRevenue(a); }).slice(0, 5);
var html = "";
for (var i = 0; i < list.length; i++) {
html += '<div class="toplist-item">' +
'<span class="toplist-rank">' + (i + 1) + '</span>' +
'<span class="toplist-city">' + list[i].name + '</span>' +
'<span class="toplist-val">' + fmtNum(cityRevenue(list[i]), 1) + ' млн ₸</span>' +
'</div>';
}
var el = $("cityTop");
if (el) el.innerHTML = html || '<div class="kt-ai-meta">Нет данных</div>';
}
function renderBars() {
var list = visibleCities().slice().sort(function (a, b) { return cityRevenue(b) - cityRevenue(a); });
var max = 0;
for (var i = 0; i < list.length; i++) {
var v = cityRevenue(list[i]);
if (v > max) max = v;
}
var html = "";
for (var j = 0; j < list.length; j++) {
var c = list[j];
var rev = cityRevenue(c);
var d = deltaPct(rev, cityJan(c));
var pct = max ? Math.max(2, Math.round((rev / max) * 100)) : 0;
var color = d >= 0 ? "var(--kt-ai-chart-blue)" : "var(--kt-ai-chart-salmon)";
html += '<button type="button" class="hbar-row" data-open-city="' + c.id + '">' +
'<span class="hbar-name">' + c.name + '</span>' +
'<span class="hbar-track"><span class="hbar-fill" style="width:' + pct + '%;background:' + color + '"></span></span>' +
'<span class="hbar-val">' + fmtNum(rev, 1) + '</span>' +
'</button>';
}
var el = $("cityBars");
if (el) el.innerHTML = html || '<div class="kt-ai-meta">Нет данных</div>';
}
function renderTable() {
var list = visibleCities().slice().sort(function (a, b) { return cityRevenue(b) - cityRevenue(a); });
var html = "";
for (var i = 0; i < list.length; i++) {
var c = list[i];
var rev = cityRevenue(c);
var d = deltaPct(rev, cityJan(c));
var tr = '<tr data-open-city="' + c.id + '" style="cursor:pointer">' +
'<td><strong>' + c.name + '</strong></td>' +
'<td>' + (state.dir ? state.dir : "Все") + '</td>' +
'<td class="num">' + c.stores + '</td>' +
'<td class="num">' + fmtInt(Math.round(c.traffic * 1000)) + '</td>' +
'<td class="num"><strong>' + fmtNum(rev, 1) + '</strong></td>' +
'<td class="num">' + fmtInt(c.avgCheck) + ' ₸</td>' +
'<td class="num">' + deltaCell(d) + '</td>' +
'<td>' + statusPill(c.status, c.statusText) + '</td>' +
'</tr>';
html += tr;
}
var tbody = $("cityTbody");
if (tbody) tbody.innerHTML = html;
var empty = $("cityEmpty");
if (empty) empty.hidden = list.length > 0;
var count = $("tableCount");
if (count) count.textContent = list.length + " из " + CITIES.length + " городов";
var sub = $("mainSub");
if (sub) sub.textContent = "Февраль 2026 · " + (state.dir || "все направления");
}
function renderMain() {
renderKpis();
renderTop();
renderBars();
renderTable();
}
function $$(sel, root) { return Array.prototype.slice.call((root || document).querySelectorAll(sel)); }
function $(id) { return document.getElementById(id); }
// ---------- Рендер: экран города ----------
function renderCity() {
var c = state.city;
if (!c) return;
var dir = null;
for (var k = 0; k < c.directions.length; k++) {
if (c.directions[k].id === state.dir) { dir = c.directions[k]; break; }
}
$("cityTitle").textContent = c.name;
var meta = c.stores + " магазинов";
if (dir) meta = "направление: " + dir.name;
$("cityMeta").textContent = meta + " · февраль 2026";
// KPI города
var rev = dir ? dir.revenue : c.revenue;
var jan = dir ? dir.jan : c.jan;
var d = deltaPct(rev, jan);
var kpi = "";
kpi += kpiCard("Выручка за февраль", fmtNum(rev, 1) + " млн ₸", "к январю: " + (d >= 0 ? "+" : "") + fmtNum(d, 1) + " %");
if (dir) {
kpi += kpiCard("Доля в выручке города", dir.shareOfCity + " %", dir.name);
} else {
kpi += kpiCard("Средний чек", fmtInt(c.avgCheck) + " ₸", "все направления");
}
kpi += kpiCard("Трафик", fmtInt(Math.round(c.traffic * 1000)) + " визитов", "в рознице за месяц");
kpi += kpiCard("Дол. розницы выручки", c.share + " %", "февраль 2026");
$("kpiCity").innerHTML = kpi;
// График по месяцам
var series = dir ? dir.trend : c.directions[0].trend.map(function (x, i) {
var s = 0;
for (var j = 0; j < c.directions.length; j++) s += c.directions[j].trend[i];
return Math.round(s * 10) / 10;
});
$("trendTitle").textContent = dir ? dir.name : "Динамика выручки";
var max = 0;
for (var m = 0; m < series.length; m++) { if (series[m] > max) max = series[m]; }
var bars = "";
for (var b = 0; b < series.length; b++) {
var h = max ? Math.max(3, Math.round((series[b] / max) * 100)) : 3;
var last = b === series.length - 1;
bars += '<div class="cc-bar" data-kt-tip="{&quot;title&quot;:&quot;' + c.name + ' — ' + MONTHS[b] + '&quot;,' +
'&quot;rows&quot;:[{&quot;label&quot;:&quot;Выручка&quot;,&quot;value&quot;:&quot;' + fmtNum(series[b], 1) + ' млн ₸&quot;}]}">' +
'<i style="height:' + h + '%;background:' + (last ? "var(--kt-ai-chart-blue)" : "var(--kt-ai-chart-bar-fill)") + ';"></i>' +
'</div>';
}
$("cityTrend").innerHTML = '<div class="cc-bars" style="height:190px">' + bars + '</div>' +
'<div class="cc-axis cc-axis-cat">' + MONTHS_SHORT.map(function (s) { return '<span>' + s + '</span>'; }).join("") + '</div>';
// Каналы продаж
var chans = dir ? dir.channels : c.channels;
var cmax = chans[0] || 1;
var chhtml = "";
for (var ch = 0; ch < CHANNEL_NAMES.length; ch++) {
var cpct = Math.max(3, Math.round((chans[ch] / cmax) * 100));
var cshare = chans[0] + chans[1] + chans[2] > 0 ? Math.round((chans[ch] / (chans[0] + chans[1] + chans[2])) * 100) : 0;
chhtml += '<div class="toplist-item" style="gap:var(--kt-ai-space-3)">' +
'<span style="flex:0 0 84px;font-size:var(--kt-ai-text-sm)">' + CHANNEL_NAMES[ch] + '</span>' +
'<span class="hbar-track" style="flex:1"><span class="hbar-fill" style="width:' + cpct + '%"></span></span>' +
'<span class="toplist-val" style="flex:0 0 96px">' + fmtNum(chans[ch], 1) + ' · ' + cshare + ' %</span>' +
'</div>';
}
$("cityChannels").innerHTML = chhtml;
$("cityShare").textContent = (dir ? dir.shareOfCity : c.share) + " %";
// Итог
var sum;
if (dir) {
sum = c.name + ": направление «" + dir.name + "» " + (d >= 0 ? "выросло" : "снижилось") + " на " + fmtNum(Math.abs(d), 1) +
" % к январю — " + fmtNum(rev, 1) + " млн ₸ за февраль. " +
(d >= 0 ? "Динамика сохраняется третий месяц подряд." : "Снижение идёт второй месяц подряд — стоит проверить ассортимент и загрузку магазинов.");
} else {
sum = c.name + ": розничная выручка за февраль — " + fmtNum(c.revenue, 1) + " млн ₸, " +
(d >= 0 ? "выше" : "ниже") + " января на " + fmtNum(Math.abs(d), 1) + " %. " +
c.stores + " магазинов дали " + fmtInt(Math.round(c.traffic * 1000)) + " визитов при среднем чеке " + fmtInt(c.avgCheck) + " ₸. " +
"Доля розницы в выручке города — " + c.share + " %.";
var up = 0, dn = 0;
for (var u = 0; u < c.directions.length; u++) {
var dd = deltaPct(c.directions[u].revenue, c.directions[u].jan);
if (dd >= 0) up++; else dn++;
}
sum += " Рост по " + up + " направлениям, снижение по " + dn + ".";
}
$("citySummary").textContent = sum;
}
// ---------- События и переходы ----------
function openCity(id) {
for (var i = 0; i < CITIES.length; i++) {
if (CITIES[i].id === id) {
state.city = CITIES[i];
break;
}
}
if (!state.city) return;
renderCity();
var main = $("screen-main");
var city = $("screen-city");
if (main) main.classList.remove("is-active");
if (city) city.classList.add("is-active");
window.scrollTo(0, 0);
}
function showMain() {
var city = $("screen-city");
var main = $("screen-main");
if (city) city.classList.remove("is-active");
if (main) main.classList.add("is-active");
window.scrollTo(0, 0);
}
function initDirSelect() {
var sel = $("dirSelect");
if (!sel) return;
var ids = ["inet", "tv", "mobile", "smart", "b2b"];
for (var i = 0; i < ids.length; i++) {
var opt = document.createElement("option");
opt.value = ids[i];
opt.textContent = DIR_LABELS[ids[i]];
sel.appendChild(opt);
}
}
function bindEvents() {
var search = $("citySearch");
if (search) {
search.addEventListener("input", function () {
state.search = this.value;
renderMain();
});
}
var dir = $("dirSelect");
if (dir) {
dir.addEventListener("change", function () {
state.dir = this.value;
renderMain();
});
}
var back = $("backBtn");
if (back) back.addEventListener("click", showMain);
document.addEventListener("click", function (e) {
var t = e.target;
while (t && t !== document && !(t.dataset && t.dataset.openCity)) {
t = t.parentNode;
}
if (t && t.dataset && t.dataset.openCity) {
openCity(t.dataset.openCity);
}
});
}
function init() {
initDirSelect();
bindEvents();
renderMain();
}
document.addEventListener("DOMContentLoaded", init);