(function () {
"use strict";
var DATA = [];
var cat = null; // активный фильтр категории (null = все)
var q = ""; // поисковый запрос
var sortKey = "f2025"; // текущая сортировка
var sortNum = true; // сортировать по числу или строке
var sortDir = -1; // -1 убыв, 1 возр
var cats = [];
function num(v) {
return v == null ? null : Number(v || 0);
}
function fmt(v) {
if (v == null) return "—";
return v.toLocaleString("ru-RU", { maximumFractionDigits: 0 });
}
function fmtPct(v) {
if (v == null) return "—";
var s = v > 0 ? "+" : "";
return s + v.toFixed(1) + " %";
}
function cls(v) {
if (v == null) return "";
return v > 0 ? "up" : (v < 0 ? "down" : "");
}
function esc(s) {
return String(s == null ? "" : s)
.replace(/&/g, "&").replace(//g, ">")
.replace(/"/g, """);
}
function formatBars() {
var rows = document.querySelectorAll("#tbl tbody tr[data-bar]");
rows.forEach(function (tr) {
var val = parseFloat(tr.dataset.bar || "0");
var max = parseFloat(tr.dataset.barmax || "1");
tr.querySelector(".bar").style.width = (max ? (val / max) * 100 : 0) + "%";
});
}
function renderTable(rows) {
var visible = rows.filter(function (r) {
if (cat && r.cat !== cat) return false;
if (q && r.name.toLowerCase().indexOf(q) < 0) return false;
return true;
});
var maxVal = 1;
visible.forEach(function (r) {
var v = num(r[sortKey]);
if (v != null && v > maxVal) maxVal = v;
});
visible.sort(function (a, b) {
var av = num(a[sortKey]);
var bv = num(b[sortKey]);
var c;
if (sortNum) {
var an = av == null ? -Infinity : av;
var bn = bv == null ? -Infinity : bv;
c = an - bn;
} else {
c = String(a[sortKey] || "").localeCompare(String(b[sortKey] || ""), "ru");
}
return c * sortDir;
});
var body = document.getElementById("tbl").querySelector("tbody");
body.innerHTML = visible.map(function (r) {
var d25 = num(r.f2025), d26 = num(r.f2026);
var delta = d25 != null && d26 != null ? d26 - d25 : null;
var deltaP = d25 != null && d26 != null && d25 !== 0 ? ((d26 - d25) / Math.abs(d25)) * 100 : null;
var barVal = sortNum ? (num(r[sortKey]) || 0) : (d25 || 0);
return "
" +
"
" + esc(r.name) + "
" +
"
" + esc(r.cat) + "
" +
"
" + fmt(d25) + "
" +
"
" + fmt(d26) + "
" +
"
" + fmt(delta) + "
" +
"
" + fmtPct(deltaP) + "
" +
"
" +
"
";
}).join("");
document.getElementById("count").textContent =
"Позиций показано: " + visible.length + " из " + rows.length;
formatBars();
}
function sumOf(rows, key) {
return rows.reduce(function (acc, r) {
var v = num(r[key]);
return v == null ? acc : acc + v;
}, 0);
}
function renderKpis(rows) {
var s25 = sumOf(rows, "f2025");
var s26 = sumOf(rows, "f2026");
var n25 = rows.filter(function (r) { return num(r.f2025) != null; }).length;
var n26 = rows.filter(function (r) { return num(r.f2026) != null; }).length;
var tot26 = s26 * 2; // экстраполяция полугодия на год — только ориентир
document.getElementById("kpis").innerHTML =
"
Итого 2025
" + fmt(s25) + "
" +
"
₸ · " + n25 + " позиций
" +
"
Итого 6 мес 2026
" + fmt(s26) + "
" +
"
₸ · " + n26 + " позиций
" +
"
2025 vs 2025 (полугодие)
" + fmt(s25 / 2) + "
" +
"
оценка среднего полугодия 2025
" +
"
Крупнейшая позиция 2025
" + fmt(s25Max(rows)) + "
" +
"
" + esc(topName(rows, "f2025")) + "
";
}
function s25Max(rows) {
var m = 0;
rows.forEach(function (r) { var v = num(r.f2025); if (v != null && v > m) m = v; });
return m;
}
function topName(rows, key) {
var best = null, bv = -1;
rows.forEach(function (r) { var v = num(r[key]); if (v != null && v > bv) { bv = v; best = r; } });
return best ? best.name : "";
}
function renderCats(rows) {
var by = {};
rows.forEach(function (r) {
if (!by[r.cat]) by[r.cat] = { name: r.cat, s25: 0, s26: 0 };
var v25 = num(r.f2025), v26 = num(r.f2026);
if (v25 != null) by[r.cat].s25 += v25;
if (v26 != null) by[r.cat].s26 += v26;
});
var total = Object.keys(by).reduce(function (a, k) { return a + by[k].s25; }, 0) || 1;
Object.keys(by).sort(function (a, b) { return by[b].s25 - by[a].s25; }).forEach(function (k) {
var c = by[k];
var pct = (c.s25 / total) * 100;
var el = document.createElement("div");
el.innerHTML =
"