201 lines
11 KiB
HTML
201 lines
11 KiB
HTML
<!doctype html>
|
||
<html lang="ru">
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||
<title>Дашборд: Захват рынка МСБ</title>
|
||
<script src="https://cdn.jsdelivr.net/npm/pptxgenjs@3.12.0/dist/pptxgen.bundle.js"></script>
|
||
<style>
|
||
* { margin: 0; box-sizing: border-box; }
|
||
body { font-family: -apple-system, "Segoe UI", Roboto, sans-serif; background: #0f1218; color: #f4f4f5; }
|
||
.slide { display: none; min-height: 100vh; padding: 6vh 8vw; flex-direction: column; justify-content: flex-start; }
|
||
.slide.on { display: flex; }
|
||
.slide h1 { font-size: clamp(28px, 5vw, 52px); margin-bottom: 20px; color: #00b8cc; }
|
||
.slide h2 { font-size: clamp(22px, 4vw, 38px); margin-bottom: 16px; color: #00b8cc; }
|
||
.slide li { font-size: clamp(16px, 2.4vw, 24px); line-height: 1.5; margin-bottom: 8px; list-style: none; padding-left: 24px; position: relative; }
|
||
.slide li::before { content: ""; position: absolute; left: 0; top: .55em; width: 10px; height: 10px; border-radius: 3px; background: #00b8cc; }
|
||
.num { position: fixed; bottom: 18px; right: 22px; color: #8a8a92; font-size: 14px; }
|
||
.nav { position: fixed; bottom: 14px; left: 22px; display: flex; gap: 8px; flex-wrap: wrap; max-width: 80vw; }
|
||
.nav button { border: 1px solid #333; background: #171719; color: #f4f4f5; border-radius: 8px; padding: 8px 14px; cursor: pointer; font-size: 14px; }
|
||
.nav .pptx { border-color: #00b8cc; color: #9beeff; }
|
||
.nav .refresh { border-color: #10b981; color: #6ee7b7; }
|
||
.metric-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 16px; margin-top: 20px; }
|
||
.metric-card { background: #1a1d24; border-radius: 10px; padding: 20px; border: 1px solid #2a2f3a; }
|
||
.metric-card h3 { font-size: 14px; color: #8a8a92; margin-bottom: 6px; }
|
||
.metric-card .value { font-size: clamp(24px, 3.5vw, 36px); font-weight: bold; color: #00b8cc; }
|
||
.metric-card .sub { font-size: 13px; color: #6a6a72; margin-top: 4px; }
|
||
.chart-placeholder { background: #1a1d24; border-radius: 12px; padding: 30px; text-align: center; margin: 16px 0; border: 1px solid #2a2f3a; }
|
||
.bar-row { display: flex; align-items: center; margin: 10px 0; }
|
||
.bar-label { width: 180px; font-size: 12px; color: #a1a1aa; }
|
||
.bar-container { flex: 1; background: #2a2f3a; border-radius: 4px; height: 22px; overflow: hidden; }
|
||
.bar { height: 100%; background: linear-gradient(90deg, #00b8cc, #0ea5e9); border-radius: 4px; transition: width 0.3s; }
|
||
.bar-value { margin-left: 10px; font-size: 13px; color: #00b8cc; min-width: 70px; text-align: right; font-weight: 600; }
|
||
.file-input { margin: 16px 0; }
|
||
.file-input input { display: none; }
|
||
.file-input label { display: inline-block; padding: 8px 16px; background: #00b8cc; color: #0f1218; border-radius: 8px; cursor: pointer; font-weight: 600; font-size: 14px; }
|
||
.file-input label:hover { background: #00d4ec; }
|
||
.rdt-section { margin: 20px 0; }
|
||
.rdt-title { font-size: 18px; color: #00b8cc; margin: 16px 0 10px 0; font-weight: 600; }
|
||
.tariff-row { display: flex; justify-content: space-between; padding: 6px 0; border-bottom: 1px solid #2a2f3a; font-size: 13px; }
|
||
.tariff-row:last-child { border-bottom: none; }
|
||
.tariff-name { color: #a1a1aa; }
|
||
.tariff-val { color: #00b8cc; font-weight: 600; }
|
||
.summary-box { background: #1a1d24; border: 1px solid #00b8cc; border-radius: 10px; padding: 20px; margin: 16px 0; }
|
||
.summary-box h3 { color: #00b8cc; margin-bottom: 12px; font-size: 18px; }
|
||
@media print {
|
||
.nav, .num, .file-input { display: none; }
|
||
.slide { display: flex; page-break-after: always; min-height: 100vh; }
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div id="deck"></div>
|
||
<div class="nav">
|
||
<button onclick="go(-1)">← Назад</button>
|
||
<button onclick="go(1)">Вперёд →</button>
|
||
<button class="pptx" onclick="downloadPptx()">📥 Скачать .pptx</button>
|
||
<button class="refresh" onclick="document.getElementById('fileInput').click()">📂 Загрузить новые данные</button>
|
||
</div>
|
||
<div class="num" id="num"></div>
|
||
|
||
<input type="file" id="fileInput" class="file-input" multiple accept=".xlsx,.xls" onchange="handleFiles(this.files)">
|
||
|
||
<script>
|
||
var RDT_DATA = [
|
||
{ name: "Восточная РДТ", paynet: 0, bastau8: 8, bastau50: 61, bastauCamCall: 2, bastauCam100: 5, horeca: 1 },
|
||
{ name: "Западная РДТ", paynet: 1, bastau8: 7, bastau50: 121, bastauCamCall: 6, bastauCam100: 60, horeca: 6 },
|
||
{ name: "РДТ Алматытелеком", paynet: 51, bastau8: 10, bastau50: 58, bastauCamCall: 10, bastauCam100: 42, horeca: 10 },
|
||
{ name: "Северная РДТ", paynet: 0, bastau8: 15, bastau50: 38, bastauCamCall: 1, bastauCam100: 10, horeca: 0 },
|
||
{ name: "Центральная РДТ", paynet: 4, bastau8: 8, bastau50: 204, bastauCamCall: 9, bastauCam100: 132, horeca: 0 },
|
||
{ name: "Южная РДТ", paynet: 15, bastau8: 42, bastau50: 51, bastauCamCall: 4, bastauCam100: 21, horeca: 2 }
|
||
];
|
||
|
||
var TOTALS = {
|
||
paynet: 71,
|
||
bastau5k: 623,
|
||
bastau7_5k: 43,
|
||
bastau10k: 270,
|
||
horeca: 19
|
||
};
|
||
|
||
var SLIDES = [];
|
||
|
||
function buildSlides() {
|
||
var totalMsb = TOTALS.paynet + TOTALS.bastau5k + TOTALS.bastau7_5k + TOTALS.bastau10k + TOTALS.horeca;
|
||
|
||
SLIDES = [
|
||
{
|
||
title: "1. ОСНОВНЫЕ ФОКУСЫ ДЛЯ АГРЕССИВНОГО ЗАХВАТА РЫНКА МСБ",
|
||
custom: function() {
|
||
var maxVal = Math.max(TOTALS.paynet, TOTALS.bastau5k, TOTALS.bastau7_5k, TOTALS.bastau10k, TOTALS.horeca);
|
||
var tariffs = [
|
||
{ name: "BASTAU 8/50 (5 000 ₸)", val: TOTALS.bastau5k, color: "#0ea5e9" },
|
||
{ name: "BASTAU CAM 100 (10 000 ₸)", val: TOTALS.bastau10k, color: "#f59e0b" },
|
||
{ name: "Paynet 5 (1 500 ₸)", val: TOTALS.paynet, color: "#00b8cc" },
|
||
{ name: "BASTAU CAM/CALL 50 (7 500 ₸)", val: TOTALS.bastau7_5k, color: "#10b981" },
|
||
{ name: "HoReCa KT (15 000 ₸)", val: TOTALS.horeca, color: "#ef4444" }
|
||
];
|
||
|
||
var bars = tariffs.map(function(t) {
|
||
var pct = maxVal > 0 ? (t.val / maxVal * 100) : 0;
|
||
return '<div class="bar-row">' +
|
||
'<div class="bar-label">' + t.name + '</div>' +
|
||
'<div class="bar-container"><div class="bar" style="width:' + pct + '%; background:' + t.color + '"></div></div>' +
|
||
'<div class="bar-value">' + t.val + ' точек</div></div>';
|
||
}).join('');
|
||
|
||
return '<div class="summary-box"><h3>📊 Итого по МСБ тарифам: ' + totalMsb.toLocaleString('ru-RU') + ' точек</h3>' + bars + '</div>' +
|
||
'<div class="metric-grid">' +
|
||
'<div class="metric-card"><h3>Paynet 5</h3><div class="value">' + TOTALS.paynet + '</div><div class="sub">1 500 ₸</div></div>' +
|
||
'<div class="metric-card"><h3>BASTAU 8/50</h3><div class="value">' + TOTALS.bastau5k + '</div><div class="sub">5 000 ₸ (ADSL + ОПТИКА)</div></div>' +
|
||
'<div class="metric-card"><h3>BASTAU CAM/CALL 50</h3><div class="value">' + TOTALS.bastau7_5k + '</div><div class="sub">7 500 ₸ (Cam + Call)</div></div>' +
|
||
'<div class="metric-card"><h3>BASTAU CAM 100</h3><div class="value">' + TOTALS.bastau10k + '</div><div class="sub">10 000 ₸</div></div>' +
|
||
'<div class="metric-card"><h3>HoReCa KT</h3><div class="value">' + TOTALS.horeca + '</div><div class="sub">15 000 ₸</div></div>' +
|
||
'</div>';
|
||
}
|
||
},
|
||
{
|
||
title: "2. Тарифы МСБ в разрезе РДТ (Август 2026)",
|
||
custom: function() {
|
||
var tariffs = [
|
||
{ name: "Paynet 5 (1 500 ₸)", data: RDT_DATA.map(function(r) { return {rdt: r.name, val: r.paynet}; }), total: TOTALS.paynet, color: "#00b8cc" },
|
||
{ name: "BASTAU 8/50 (5 000 ₸)", data: RDT_DATA.map(function(r) { return {rdt: r.name, val: r.bastau8 + r.bastau50}; }), total: TOTALS.bastau5k, color: "#0ea5e9" },
|
||
{ name: "BASTAU CAM/CALL 50 (7 500 ₸)", data: RDT_DATA.map(function(r) { return {rdt: r.name, val: r.bastauCamCall}; }), total: TOTALS.bastau7_5k, color: "#10b981" },
|
||
{ name: "BASTAU CAM 100 (10 000 ₸)", data: RDT_DATA.map(function(r) { return {rdt: r.name, val: r.bastauCam100}; }), total: TOTALS.bastau10k, color: "#f59e0b" },
|
||
{ name: "HoReCa KT (15 000 ₸)", data: RDT_DATA.map(function(r) { return {rdt: r.name, val: r.horeca}; }), total: TOTALS.horeca, color: "#ef4444" }
|
||
];
|
||
|
||
return tariffs.map(function(t) {
|
||
var maxVal = Math.max.apply(null, t.data.map(function(d) { return d.val; })) || 1;
|
||
var sortedData = t.data.sort(function(a,b) { return b.val - a.val; });
|
||
var bars = sortedData.map(function(d) {
|
||
var pct = maxVal > 0 ? (d.val / maxVal * 100) : 0;
|
||
return '<div class="bar-row">' +
|
||
'<div class="bar-label">' + d.rdt + '</div>' +
|
||
'<div class="bar-container"><div class="bar" style="width:' + pct + '%; background:' + t.color + '"></div></div>' +
|
||
'<div class="bar-value">' + d.val + '</div></div>';
|
||
}).join('');
|
||
|
||
return '<div class="rdt-section">' +
|
||
'<div class="rdt-title" style="color:' + t.color + '">' + t.name + ' — ' + t.total + ' точек всего</div>' +
|
||
bars +
|
||
'</div>';
|
||
}).join('');
|
||
}
|
||
}
|
||
];
|
||
}
|
||
|
||
var cur = 0;
|
||
|
||
function render() {
|
||
var deck = document.getElementById("deck");
|
||
deck.innerHTML = SLIDES.map(function (s, i) {
|
||
var content = s.custom ? s.custom() : '<ul>' + s.bullets.map(function (b) { return "<li>" + b + "</li>"; }).join("") + '</ul>';
|
||
return '<section class="slide' + (i === cur ? " on" : "") + '">' +
|
||
'<h1>' + s.title + '</h1>' + content + '</section>';
|
||
}).join("");
|
||
document.getElementById("num").textContent = (cur + 1) + " / " + SLIDES.length;
|
||
}
|
||
|
||
function go(d) {
|
||
cur = Math.min(SLIDES.length - 1, Math.max(0, cur + d));
|
||
render();
|
||
}
|
||
|
||
document.addEventListener("keydown", function (e) {
|
||
if (e.key === "ArrowRight" || e.key === " ") go(1);
|
||
if (e.key === "ArrowLeft") go(-1);
|
||
});
|
||
|
||
function downloadPptx() {
|
||
var p = new PptxGenJS();
|
||
p.defineLayout({ name: "W", width: 13.33, height: 7.5 });
|
||
p.layout = "W";
|
||
|
||
SLIDES.forEach(function (s) {
|
||
var sl = p.addSlide();
|
||
sl.background = { color: "0F1218" };
|
||
sl.addText(s.title, { x: 0.5, y: 0.4, w: 12.3, h: 1, fontSize: 28, bold: true, color: "00B8CC" });
|
||
|
||
if (s.bullets && s.bullets.length > 0) {
|
||
var bulletPoints = s.bullets.filter(function(b) { return b; }).map(function(b) {
|
||
return { text: b, options: { bullet: true, breakLine: true, fontSize: 18, color: "E4E4E7" } };
|
||
});
|
||
sl.addText(bulletPoints, { x: 0.7, y: 1.6, w: 12, h: 5, lineSpacingMultiple: 1.4 });
|
||
}
|
||
});
|
||
|
||
p.writeFile({ fileName: "MSB_dashboard_" + new Date().toISOString().slice(0,10) + ".pptx" });
|
||
}
|
||
|
||
function handleFiles(files) {
|
||
alert('Файлов выбрано: ' + files.length + '\\n\\nДанные встроены в код.\\nДля обновления — отправьте новые Excel-файлы, я обновлю дашборд.');
|
||
}
|
||
|
||
buildSlides();
|
||
render();
|
||
</script>
|
||
</body>
|
||
</html>
|