489 lines
21 KiB
JavaScript
489 lines
21 KiB
JavaScript
/* Дашборд розничных продаж по городам: данные, фильтры, два экрана */
|
||
(function () {
|
||
"use strict";
|
||
|
||
/* ================= ДАННЫЕ ================= */
|
||
|
||
var MONTHS = ["январь", "февраль", "март", "апрель", "май", "июнь", "июль", "август"];
|
||
var MONTHS_SHORT = ["янв", "фев", "мар", "апр", "май", "июн", "июл", "авг"];
|
||
|
||
var CITIES = [
|
||
{ name: "Алматы", region: "Юг", salesT2: 486, salesT: 512, ticketsT: 78.4, avgT: 6530, growth: 5.3, top: "Мобильные устройства" },
|
||
{ name: "Астана", region: "Север", salesT2: 342, salesT: 358, ticketsT: 52.1, avgT: 6870, growth: 4.7, top: "Телевизоры" },
|
||
{ name: "Шымкент", region: "Юг", salesT2: 176, salesT: 189, ticketsT: 34.2, avgT: 5530, growth: 7.4, top: "Бытовая техника" },
|
||
{ name: "Караганда", region: "Север", salesT2: 148, salesT: 142, ticketsT: 27.9, avgT: 5090, growth: -4.1, top: "Домашний интернет" },
|
||
{ name: "Актау", region: "Запад", salesT2: 121, salesT: 134, ticketsT: 21.6, avgT: 6200, growth: 10.7, top: "Электроника" },
|
||
{ name: "Акмола", region: "Север", salesT2: 114, salesT: 121, ticketsT: 23.8, avgT: 5080, growth: 6.1, top: "Домашний интернет" },
|
||
{ name: "Актобе", region: "Запад", salesT2: 108, salesT: 112, ticketsT: 22.4, avgT: 5000, growth: 3.7, top: "Бытовая техника" },
|
||
{ name: "Костанай", region: "Север", salesT2: 96, salesT: 101, ticketsT: 20.3, avgT: 4970, growth: 5.2, top: "Телефония" },
|
||
{ name: "Павлодар", region: "Север", salesT2: 88, salesT: 84, ticketsT: 17.1, avgT: 4910, growth: -4.5, top: "Телевизоры" },
|
||
{ name: "Усть-Каменогорск", region: "Восток", salesT2: 72, salesT: 78, ticketsT: 14.9, avgT: 5230, growth: 8.3, top: "Бытовая техника" }
|
||
];
|
||
|
||
/* товарные категории и базовые веса долей */
|
||
var CATS = [
|
||
{ key: "phone", label: "Телефония", w: 0.24 },
|
||
{ key: "mob", label: "Мобильные устройства", w: 0.19 },
|
||
{ key: "tv", label: "Телевизоры", w: 0.12 },
|
||
{ key: "bt", label: "Бытовая техника", w: 0.11 },
|
||
{ key: "elec", label: "Электроника", w: 0.10 },
|
||
{ key: "home", label: "Домашний интернет", w: 0.08 },
|
||
{ key: "acc", label: "Аксессуары", w: 0.06 },
|
||
{ key: "other", label: "Прочее", w: 0.10 }
|
||
];
|
||
|
||
var SEEDS = {
|
||
"Алматы": [1.05, 1.10, 0.95, 0.80, 0.60, 0.90, 1.00, 1.00],
|
||
"Астана": [0.90, 1.00, 0.70, 1.15, 0.65, 0.85, 1.05, 1.00],
|
||
"Шымкент": [1.10, 0.95, 0.90, 0.75, 0.85, 1.05, 0.95, 1.00],
|
||
"Караганда": [0.85, 0.95, 1.05, 0.90, 0.70, 0.80, 1.00, 1.00],
|
||
"Актау": [1.00, 0.90, 1.15, 0.85, 0.75, 0.95, 0.90, 1.00],
|
||
"Акмола": [0.95, 0.80, 1.05, 1.00, 0.70, 0.85, 0.95, 1.00],
|
||
"Актобе": [0.80, 1.05, 0.90, 0.85, 0.95, 0.75, 1.10, 1.00],
|
||
"Костанай": [1.00, 0.85, 0.90, 1.05, 0.80, 0.95, 1.00, 1.00],
|
||
"Павлодар": [0.90, 1.00, 0.75, 0.85, 1.05, 0.70, 0.90, 1.00],
|
||
"Усть-Каменогорск": [0.95, 1.05, 0.80, 0.90, 1.00, 0.85, 0.70, 1.00]
|
||
};
|
||
|
||
var state = {
|
||
q: "",
|
||
region: "all",
|
||
sort: "sales",
|
||
viewed: {}
|
||
};
|
||
|
||
var el = {};
|
||
var LS_KEY = "kt-dash-rozn-2";
|
||
|
||
function saveState() {
|
||
try {
|
||
localStorage.setItem(LS_KEY, JSON.stringify({
|
||
q: state.q,
|
||
region: state.region,
|
||
sort: state.sort,
|
||
viewed: state.viewed
|
||
}));
|
||
} catch (e) { /* приватный режим — молча */ }
|
||
}
|
||
|
||
function loadState() {
|
||
try {
|
||
var raw = localStorage.getItem(LS_KEY);
|
||
if (!raw) { return; }
|
||
var saved = JSON.parse(raw);
|
||
if (typeof saved.q === "string") { state.q = saved.q.slice(0, 40); }
|
||
if (typeof saved.region === "string") { state.region = saved.region; }
|
||
if (["sales", "growth", "avg", "share"].indexOf(saved.sort) !== -1) { state.sort = saved.sort; }
|
||
if (saved.viewed && typeof saved.viewed === "object") { state.viewed = saved.viewed; }
|
||
} catch (e) { /* битые данные — начинаем с чистого */ }
|
||
}
|
||
|
||
/* ================= ХЕЛПЕРЫ ================= */
|
||
|
||
function $(id) { return document.getElementById(id); }
|
||
|
||
function fmtNum(n, dec) {
|
||
dec = dec || 0;
|
||
var s = String(Number(n.toFixed(dec)));
|
||
var parts = s.split(".");
|
||
var int = parts[0];
|
||
var out = "";
|
||
while (int.length > 3) {
|
||
out = " " + int.slice(-3) + out;
|
||
int = int.slice(0, -3);
|
||
}
|
||
out = int + out;
|
||
return parts.length > 1 ? out + "," + parts[1] : out;
|
||
}
|
||
|
||
function esc(s) {
|
||
return String(s).replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
||
}
|
||
|
||
function totalSales(list, field) {
|
||
var t = 0;
|
||
for (var i = 0; i < list.length; i++) { t += list[i][field]; }
|
||
return t;
|
||
}
|
||
|
||
function cityByIdx(name) {
|
||
for (var i = 0; i < CITIES.length; i++) {
|
||
if (CITIES[i].name === name) { return CITIES[i]; }
|
||
}
|
||
return null;
|
||
}
|
||
|
||
function growthPill(g) {
|
||
if (g > 0) { return '<span class="kt-ai-status-pill" data-status="ok">+' + g.toFixed(1) + "%</span>"; }
|
||
if (g < 0) { return '<span class="kt-ai-status-pill" data-status="risk">' + g.toFixed(1) + "%</span>"; }
|
||
return '<span class="kt-ai-status-pill" data-status="muted">0,0%</span>';
|
||
}
|
||
|
||
/* продажи города по месяцам, млн тг */
|
||
function monthlySales(c) {
|
||
var s = SEEDS[c.name] || [];
|
||
var arr = [];
|
||
for (var i = 0; i < MONTHS.length; i++) {
|
||
arr.push(Math.round(c.salesT * (s[i] || 1) * 10) / 10);
|
||
}
|
||
return arr;
|
||
}
|
||
|
||
/* доли товарных категорий, % */
|
||
function cityCats(c) {
|
||
var s = SEEDS[c.name] || [];
|
||
var arr = [];
|
||
for (var i = 0; i < CATS.length; i++) {
|
||
var m = s[i % s.length] || 1;
|
||
arr.push({ label: CATS[i].label, share: Math.round(CATS[i].w * m * 100) / 100 });
|
||
}
|
||
return arr;
|
||
}
|
||
|
||
/* топ-позиции: имя + доля в продажах */
|
||
function topItems(c) {
|
||
var cats = cityCats(c);
|
||
var names = {
|
||
"phone": { a: "Абонентский план «Безлимит 50»", b: "Абонентский план «Семейный»" },
|
||
"mob": { a: "Смартфон Galaxy S24", b: "Смартфон iPhone 15" },
|
||
"tv": { a: "Телевизор 55\" 4K", b: "Телевизор 43\" FHD" },
|
||
"bt": { a: "Холодильник No Frost", b: "Микроволновая печь" },
|
||
"elec": { a: "Ноутбук 15\"", b: "Монитор 27\"" },
|
||
"home": { a: "Домашний интернет 300 Мбит/с", b: "Домашний интернет 100 Мбит/с" },
|
||
"acc": { a: "Беспроводные наушники", b: "Зарядное устройство USB-C" },
|
||
"other": { a: "Услуга аренды линии", b: "Подписка на видеосервис" }
|
||
};
|
||
var sorted = cats.slice().sort(function (a, b) { return b.share - a.share; });
|
||
var out = [];
|
||
out.push({ name: c.top, share: null });
|
||
var max = 0;
|
||
for (var i = 0; i < sorted.length; i++) {
|
||
if (sorted[i].label === c.top) { out[0].share = sorted[i].share; max = Math.max(max, sorted[i].share); }
|
||
}
|
||
for (var j = 0; j < sorted.length && out.length < 4; j++) {
|
||
if (sorted[j].label === c.top) { continue; }
|
||
var nm = names[CATS[j].key];
|
||
var pick = (j % 2 === 0) ? nm.a : nm.b;
|
||
out.push({ name: pick, share: Math.round(sorted[j].share * 0.8 * 10) / 10 });
|
||
max = Math.max(max, out[out.length - 1].share);
|
||
}
|
||
for (var k = 0; k < out.length; k++) {
|
||
var s10 = Math.round(out[k].share) * 10;
|
||
out[k].pct = (out[k].share && s10 > 0) ? Math.max(8, Math.min(100, Math.round(s10 / 2))) : 100;
|
||
}
|
||
return out;
|
||
}
|
||
|
||
/* ================= ГЛАВНЫЙ ЭКРАН ================= */
|
||
|
||
function filteredCities() {
|
||
var q = state.q.toLowerCase();
|
||
var out = [];
|
||
for (var i = 0; i < CITIES.length; i++) {
|
||
var c = CITIES[i];
|
||
if (state.region !== "all" && c.region !== state.region) { continue; }
|
||
if (q && c.name.toLowerCase().indexOf(q) === -1) { continue; }
|
||
out.push(c);
|
||
}
|
||
var key = state.sort;
|
||
out.sort(function (a, b) {
|
||
if (key === "growth") { return b.growth - a.growth; }
|
||
if (key === "avg") { return b.avgT - a.avgT; }
|
||
if (key === "share") { return b.salesT - a.salesT; }
|
||
return b.salesT - a.salesT;
|
||
});
|
||
return out;
|
||
}
|
||
|
||
function renderKpi(all) {
|
||
var sumT = totalSales(all, "salesT");
|
||
var sumT2 = totalSales(all, "salesT2");
|
||
var cnt = 0;
|
||
for (var i = 0; i < all.length; i++) {
|
||
if (all[i].growth > 0) { cnt++; }
|
||
}
|
||
var top = all.length ? all.slice().sort(function (a, b) { return b.salesT - a.salesT; })[0] : null;
|
||
var avg = sumT ? Math.round(sumT / all.length) : 0;
|
||
var revisit = null;
|
||
for (var v = 0; v < all.length; v++) {
|
||
var seen = state.viewed[all[v].name];
|
||
if (seen && seen.sales != null && all[v].salesT !== seen.sales) {
|
||
if (!revisit || all[v].salesT < revisit.salesT) { revisit = all[v]; }
|
||
}
|
||
}
|
||
html(
|
||
'<div class="kt-ai-kpi"><span class="label">Выручка</span>' +
|
||
'<span class="value">' + fmtNum(sumT) + " млн ₸</span><span class=\"hint\">" + all.length + (all.length === 1 || (all.length >= 2 && all.length <= 4) ? " город" : " городов") + "</span></div>" +
|
||
'<div class="kt-ai-kpi"><span class="label">Доля в сети</span>' +
|
||
'<span class="value">' + (top ? top.name : "—") + "</span><span class=\"hint\">лидер продаж</span></div>" +
|
||
'<div class=\"kt-ai-kpi\"><span class=\"label\">Средний город</span>' +
|
||
"<span class=\"value\">" + fmtNum(avg) + " млн ₸</span><span class=\"hint\">по " + all.length + " городам</span></div>" +
|
||
'<div class="kt-ai-kpi"><span class="label">Растут к прош. периоду</span>' +
|
||
"<span class=\"value\">" + cnt + " из " + all.length + "</span><span class=\"hint\">" + (all.length ? Math.round(cnt / all.length * 100) : 0) + "% городов</span></div>" +
|
||
(revisit
|
||
? '<div class="kt-ai-kpi"><span class="label">Повторно посетите</span>' +
|
||
'<span class="value" data-revisit="' + esc(revisit.name) + '" title="Открыть ' + esc(revisit.name) + '">' + esc(revisit.name) + "</span>" +
|
||
'<span class="hint">продажи изменились с прошлого просмотра</span></div>'
|
||
: "")
|
||
);
|
||
}
|
||
|
||
function renderCities() {
|
||
var list = filteredCities();
|
||
var all = CITIES;
|
||
renderKpi(list.length ? list : all);
|
||
|
||
var maxSum = 0;
|
||
var sum = totalSales(all, "salesT");
|
||
for (var i = 0; i < all.length; i++) {
|
||
maxSum = Math.max(maxSum, all[i].salesT);
|
||
}
|
||
|
||
var rows = "";
|
||
for (var r = 0; r < list.length; r++) {
|
||
var c = list[r];
|
||
var share = sum ? (c.salesT / sum * 100) : 0;
|
||
var barW = maxSum ? Math.max(4, Math.round(c.salesT / maxSum * 100)) : 0;
|
||
rows +=
|
||
'<tr data-city="' + esc(c.name) + '" style="cursor:pointer">' +
|
||
'<td><div class="city-cell"><span class="city-name">' + esc(c.name) + "</span>" +
|
||
'<span class="city-meta">' + esc(c.region) + " · топ: " + esc(c.top) + "</span></div></td>" +
|
||
'<td class="num"><div class="share-cell">' +
|
||
'<span class="share-value">' + fmtNum(c.salesT) + " млн ₸</span>" +
|
||
'<span class="share-track"><span class="share-fill" style="width:' + barW + '%"></span></span></div></td>' +
|
||
"<td class=\"num\">" + growthPill(c.growth) + "</td>" +
|
||
'<td class="num">' + fmtNum(c.avgT) + " ₸</td>" +
|
||
'<td class="num">' + share.toFixed(1) + "%</td>" +
|
||
'<td><span class="row-go" aria-hidden="true">›</span></td>' +
|
||
"</tr>";
|
||
}
|
||
$("cities-tbody").innerHTML = rows;
|
||
|
||
$("cities-count").textContent = list.length + " из " + all.length + " городов";
|
||
|
||
var empty = $("cities-empty");
|
||
if (!list.length) {
|
||
empty.innerHTML =
|
||
'<div class="kt-ai-empty">' +
|
||
'<svg class="kt-icon kt-icon-lg"><use href="#search"></use></svg>' +
|
||
"<p>Ничего не найдено</p>" +
|
||
'<button class="kt-ai-btn" data-size="sm" id="btn-reset">Сбросить фильтры</button>' +
|
||
"</div>";
|
||
var b = $("btn-reset");
|
||
if (b) { b.addEventListener("click", function () { resetFilters(); }); }
|
||
} else {
|
||
empty.innerHTML = "";
|
||
}
|
||
}
|
||
|
||
function resetFilters() {
|
||
state.q = "";
|
||
state.region = "all";
|
||
if (el.search) { el.search.value = ""; }
|
||
renderCities();
|
||
}
|
||
|
||
function renderRegionChips() {
|
||
var regions = [];
|
||
for (var i = 0; i < CITIES.length; i++) {
|
||
var rg = CITIES[i].region;
|
||
if (regions.indexOf(rg) === -1) { regions.push(rg); }
|
||
}
|
||
var h = '<div class="chips-row kt-ai-filterbar">';
|
||
h += chip("Все", "all", state.region === "all");
|
||
for (var j = 0; j < regions.length; j++) {
|
||
h += chip(regions[j], regions[j], state.region === regions[j]);
|
||
}
|
||
h += "</div>";
|
||
$("filters-cities").innerHTML = h;
|
||
}
|
||
|
||
function chip(label, value, active) {
|
||
return '<button class="kt-ai-btn" data-size="sm" data-region="' + esc(value) + '" data-variant="' + (active ? "primary" : "ghost") + '">' + esc(label) + "</button>";
|
||
}
|
||
|
||
/* ================= ДЕТАЛЬНЫЙ ЭКРАН ================= */
|
||
|
||
function renderCity(name) {
|
||
var c = cityByIdx(name);
|
||
if (!c) { return; }
|
||
state.viewed[c.name] = { sales: c.salesT };
|
||
saveState();
|
||
var monthly = monthlySales(c);
|
||
var maxM = 0;
|
||
for (var i = 0; i < monthly.length; i++) { maxM = Math.max(maxM, monthly[i]); }
|
||
|
||
var bars = "";
|
||
for (var b = 0; b < monthly.length; b++) {
|
||
var h = maxM ? Math.max(3, Math.round(monthly[b] / maxM * 100)) : 3;
|
||
bars += '<div class="cc-bar" tabindex="0" data-kt-tip="' + esc(MONTHS[b]) + ": " + fmtNum(monthly[b]) + ' млн ₸"><i style="height:' + h + '%"></i></div>';
|
||
}
|
||
var axis = "";
|
||
for (var a = 0; a < MONTHS_SHORT.length; a++) { axis += "<span>" + esc(MONTHS_SHORT[a]) + "</span>"; }
|
||
|
||
var cats = cityCats(c);
|
||
var catRows = "";
|
||
for (var k = 0; k < cats.length; k++) {
|
||
catRows +=
|
||
"<tr>" +
|
||
'<td><div class="cat-cell"><span class="cat-name">' + esc(cats[k].label) + "</span></div></td>" +
|
||
'<td class="num">' + fmtNum(cats[k].share, 1) + "%</td>" +
|
||
"</tr>";
|
||
}
|
||
|
||
var tops = topItems(c);
|
||
var topRows = "";
|
||
for (var t = 0; t < tops.length; t++) {
|
||
topRows +=
|
||
"<tr>" +
|
||
"<td>" + (t + 1) + "</td>" +
|
||
"<td>" + esc(tops[t].name) + "<div class=\"cta-bar\"><span style=\"width:" + tops[t].pct + "%\"></span></div></td>" +
|
||
"</tr>";
|
||
}
|
||
|
||
var sumT = c.salesT;
|
||
var sumT2 = c.salesT2;
|
||
var diff = sumT - sumT2;
|
||
var trend = diff >= 0
|
||
? "Продажи выросли на " + fmtNum(Math.abs(diff)) + " млн ₸ к прошлому периоду."
|
||
: "Продажи снизились на " + fmtNum(Math.abs(diff)) + " млн ₸ к прошлому периоду.";
|
||
|
||
$("city-content").innerHTML =
|
||
'<div class="kt-ai-page-title-block">' +
|
||
'<button class="kt-ai-btn" data-variant="ghost" data-size="sm" id="btn-back" style="margin-bottom:var(--kt-ai-space-2)"><svg class="kt-icon kt-icon-sm"><use href="#chevronLeft"></use></svg>К городам</button>' +
|
||
'<h1 class="kt-ai-h1">' + esc(c.name) + "</h1>" +
|
||
'<p class="kt-ai-sub">' + esc(c.region) + " · розничные продажи за отчётный период</p>" +
|
||
"</div>" +
|
||
|
||
'<div class="kt-ai-kpi-strip">' +
|
||
'<div class="kt-ai-kpi"><span class="label">Выручка</span><span class="value">' + fmtNum(sumT) + " млн ₸</span><span class=\"hint\">прошлый период: " + fmtNum(sumT2) + " млн ₸</span></div>" +
|
||
'<div class="kt-ai-kpi"><span class="label">Динамика</span><span class="value">' + (diff >= 0 ? "+" : "") + fmtNum(diff) + " млн ₸</span><span class=\"hint\">" + diff >= 0 ? "рост" : "снижение" + "</span></div>" +
|
||
'<div class="kt-ai-kpi"><span class="label">Чексредний</span><span class="value">' + fmtNum(c.avgT) + " ₸</span><span class=\"hint\">" + fmtNum(c.ticketsT) + " тыс. покупок</span></div>" +
|
||
"</div>" +
|
||
|
||
'<div class="city-grid">' +
|
||
'<section class="kt-ai-chart-card">' +
|
||
'<div class="cc-head"><div><div class="cc-title">Продажи по месяцам</div>' +
|
||
'<div class="cc-sub">млн ₸ · ' + esc(c.name) + "</div></div></div>" +
|
||
'<div class="cc-bars">' + bars + "</div>" +
|
||
'<div class="cc-axis">' + axis + "</div>" +
|
||
"</section>" +
|
||
|
||
'<section class="kt-ai-chart-card" style="--cc-color:var(--kt-ai-chart-green)">' +
|
||
'<div class="cc-head"><div><div class="cc-title">Топ позиций</div>' +
|
||
'<div class="cc-sub">доля позиции в продажах города</div></div></div>' +
|
||
topRows ? '<div class="kt-ai-table-wrap" data-framed="false"><table class="kt-ai-table" data-density="compact"><tbody>' + topRows + "</tbody></table></div>" : "" +
|
||
"</section>" +
|
||
"</div>" +
|
||
|
||
'<section class="kt-ai-chart-card">' +
|
||
'<div class="cc-head"><div><div class="cc-title">Продажи по товарным категориям</div>' +
|
||
'<div class="cc-sub">доля категории в продажах города</div></div></div>' +
|
||
'<div class="kt-ai-table-wrap">' +
|
||
'<table class="kt-ai-table"><thead><tr><th>Категория</th><th class="num">Доля</th></tr></thead>' +
|
||
"<tbody>" + catRows + "</tbody></table>" +
|
||
"</div></section>" +
|
||
|
||
'<section class="kt-ai-conclusion">' +
|
||
'<span class="title">Что показывают эти данные</span>' +
|
||
'<span class="text">' + esc(trend) + " Ведущая позиция города — " + esc(c.top.toLowerCase()) + ". " +
|
||
(c.growth > 0 ? "Динамика положительная: " : "Динамика отрицательная: ") +
|
||
fmtNum(Math.abs(c.growth), 1) + "% к прошлому периоду.</span>" +
|
||
"</section>";
|
||
}
|
||
|
||
/* ================= НАВИГАЦИЯ / СОБЫТИЯ ================= */
|
||
|
||
function setView(v) {
|
||
state.view = v;
|
||
state.city = v === "city" ? state.city : null;
|
||
var main = $("view-cities");
|
||
var detail = $("view-city");
|
||
var crumb = document.querySelector("[data-crumb]");
|
||
if (v === "cities") {
|
||
main.hidden = false;
|
||
detail.hidden = true;
|
||
crumb.innerHTML = "Розничные продажи <strong>/</strong> <strong>Города</strong>";
|
||
window.scrollTo(0, 0);
|
||
} else {
|
||
main.hidden = true;
|
||
detail.hidden = false;
|
||
crumb.innerHTML = "Розничные продажи <strong>/</strong> <strong>" + esc(state.city || "") + "</strong>";
|
||
renderCity(state.city);
|
||
window.scrollTo(0, 0);
|
||
}
|
||
}
|
||
|
||
function init() {
|
||
loadState();
|
||
el.search = $("search-cities");
|
||
el.cities = $("view-cities");
|
||
|
||
el.search.addEventListener("input", function () {
|
||
state.q = el.search.value.trim();
|
||
renderCities();
|
||
saveState();
|
||
});
|
||
|
||
var sortWrap = $("sort-cities");
|
||
sortWrap.addEventListener("click", function (e) {
|
||
var btn = e.target.closest(".seg");
|
||
if (!btn) { return; }
|
||
state.sort = btn.getAttribute("data-sort");
|
||
updateSort();
|
||
renderCities();
|
||
saveState();
|
||
});
|
||
|
||
el.cities.addEventListener("click", function (e) {
|
||
var row = e.target.closest("tr[data-city]");
|
||
if (row) {
|
||
state.city = row.getAttribute("data-city");
|
||
setView("city");
|
||
return;
|
||
}
|
||
var reg = e.target.closest("[data-region]");
|
||
if (reg) {
|
||
state.region = reg.getAttribute("data-region");
|
||
renderRegionChips();
|
||
renderCities();
|
||
saveState();
|
||
}
|
||
var revisit = e.target.closest("[data-revisit]");
|
||
if (revisit) {
|
||
state.city = revisit.getAttribute("data-revisit");
|
||
setView("city");
|
||
}
|
||
});
|
||
|
||
$("view-city").addEventListener("click", function (e) {
|
||
if (e.target.closest("#btn-back")) { setView("cities"); }
|
||
});
|
||
|
||
if (el.search) { el.search.value = state.q; }
|
||
if (["sales", "growth", "avg", "share"].indexOf(state.sort) === -1) { state.sort = "sales"; }
|
||
|
||
renderRegionChips();
|
||
renderCities();
|
||
updateSort();
|
||
}
|
||
|
||
function updateSort() {
|
||
var btns = document.querySelectorAll("#sort-cities .seg");
|
||
for (var i = 0; i < btns.length; i++) {
|
||
var active = btns[i].getAttribute("data-sort") === state.sort;
|
||
btns[i].setAttribute("data-active", active ? "true" : "false");
|
||
}
|
||
}
|
||
|
||
function html(s) {
|
||
$("kpi-cities").innerHTML = s;
|
||
}
|
||
|
||
if (document.readyState === "loading") {
|
||
document.addEventListener("DOMContentLoaded", init);
|
||
} else {
|
||
init();
|
||
}
|
||
})();
|