/* Сводный финансовый анализ дочерних компаний — статичный макет, состояние в localStorage */
(function () {
"use strict";
var LS = "sfa-do-v1";
function loadState() {
var base = { screen: "upload", fileStatus: {}, fileManual: false, mappingMode: "auto", unitFixed: [], deviations: [], aiAccepted: false, sent: false, analysis: {}, done: { recognize: true, check: false, analysis: false, result: false }, theme: "light" };
try {
var raw = localStorage.getItem(LS);
if (raw) { var s = JSON.parse(raw); for (var k in base) if (s && k in s) base[k] = s[k]; }
} catch (e) { if (!localStorage.getItem(LS)) base.resetFlag = true; }
return base;
}
function save() { try { localStorage.setItem(LS, JSON.stringify(S)); } catch (e) {} }
var S = loadState();
var COMPANIES = [
["ООО А", 12500, 11800, 3100, 3050, 420, 510, 640, 590, 1840, 2110, 1240, 1215],
["ООО Б", 8200, 7950, 2100, 1980, 280, 310, 410, 390, 1220, 1150, 860, 842],
["ООО В", 15400, 13100, 4100, 3480, 530, 470, 880, 720, 2450, 2610, 1580, 1595],
["ООО Г", 9800, 10050, 2500, 2560, 340, 355, 520, 480, 1480, 1390, 1010, 998],
["ООО Д", 11300, 10900, 2850, 2700, 390, 430, 610, 585, 1620, 1705, 1130, 1128],
["ООО Е", 7600, 7420, 1900, 1830, 250, 270, 380, 350, 1090, 1160, 780, 775],
["ООО Ж", 13900, 14350, 3600, 3720, 480, 455, 760, 730, 2180, 2040, 1420, 1408],
["ООО З", 6700, 6510, 1680, 1610, 220, 240, 330, 300, 960, 1015, 690, 682],
["ООО И", 10400, 9980, 2640, 2490, 360, 385, 570, 545, 1490, 1565, 1040, 1035],
["ООО К", 8900, 8730, 2280, 2210, 300, 325, 450, 420, 1270, 1335, 915, 908],
["ООО Л", 12100, 12490, 3200, 3310, 430, 415, 690, 660, 1740, 1650, 1265, 1258],
["ООО М", 7100, 6890, 1780, 1720, 260, 280, 400, 365, 1030, 1085, 745, 740],
["ООО Н", 14600, 13850, 3850, 3640, 505, 525, 830, 790, 2320, 2415, 1495, 1488],
["ООО О", 9300, 8910, 2380, 2240, 330, 350, 510, 480, 1360, 1425, 965, 958],
["ООО П", 11700, 11980, 3000, 3080, 405, 395, 640, 615, 1580, 1495, 1175, 1168],
["ООО Р", 8400, 8160, 2150, 2060, 290, 310, 430, 400, 1180, 1240, 835, 830],
["ООО С", 13200, 12840, 3400, 3280, 460, 485, 710, 680, 1950, 2020, 1355, 1348]
];
var CO = COMPANIES.map(function (r) { return { name: r[0], vp: r[1], vf: r[2], ep: r[3], ef: r[4], cap: r[5], caf: r[6], dp: r[7], df: r[8], cp: r[9], cf: r[10], hp: r[11], hf: r[12] }; });
function dev(o, f, v) { return v > 0 ? Math.round(Math.abs(f - v) / v * 1000) / 10 : 0; }
CO.forEach(function (c) {
c.rDev = dev(c, c.vf, c.vp); c.eDev = dev(c, c.ef, c.ep); c.cDev = dev(c, c.caf, c.cap);
c.dDev = dev(c, c.df, c.dp); c.kDev = dev(c, c.cf, c.cp); c.maxDev = Math.max(c.rDev, c.eDev, c.cDev, c.dDev, c.kDev);
});
var FILES = [
["Отчет_ОАОА_июнь.xlsx", 0], ["Fin_report_ООО-Б_0626.xlsx", 1], ["Свод_В_план_факт.xlsx", 2],
["Отчет_Г_июнь_2026.xlsx", 3], ["Fin_Д_06-2026.xlsx", 4], ["Финансы_Е_июнь.xlsx", 5],
["Отчет_Ж.xlsx", 6], ["Годовой_отчет_З.xlsx", 7], ["Данные_И_июнь.xlsx", 8],
["Report_K_2026-06.xlsx", 9], ["Свод_Л_июнь.xlsx", 10], ["Fin_М_06.xlsx", 11],
["Отчет_Н_июнь_2026.xlsx", 12], ["Data_O_2026.06.xlsx", 13], ["Отчет_П.xlsx", 14],
["Фин_Р_июнь.xlsx", 15], ["Summary_S_06.2026.xlsx", 16]
];
var MAPPING = [
["Выручка", { 0: "Раздел_1_Оборот", 1: "Выручка_в_тыс", 2: "Выручка", 3: "ОБорот_за_отчетный_период", 4: "Revenue", 5: "ОП_Выручка", 6: "Выручка(нетто)", 7: "Выручка год", 8: "ОП-1 Выручка", 9: "REV_06", 10: "Выручка", 11: "Rev", 12: "Выручка", 13: "Sales", 14: "О_п_факт", 15: "Выручка_итоги", 16: "Revenue_06" }],
["EBITDA", { 0: "EBITDA", 1: "Прибыль_до_аморт", 2: "EBITDA_план", 3: "EBITDA факт", 4: "EBITDA", 5: "EBITDA_итого", 6: "Прибыль_EBITDA", 7: "EBITDA_год", 8: "EBITDA факт", 9: "EBITDA_06", 10: "EBITDA", 11: "eBITDA", 12: "EBITDA факт", 13: "EBITDA", 14: "EBITDA_факт", 15: "EBITDA", 16: "EBITDA_06" }],
["CAPEX", { 0: "Инвест_затраты", 1: "Капзатраты_тыс", 2: "CAPEX", 3: "Инвестпроект_затраты", 4: "Capex", 5: "CAPEX_итоги", 6: "Инвест.затраты", 7: "CAPEX_год", 8: "CAPEX факт", 9: "CAPEX_06", 10: "CAPEX", 11: "capex", 12: "CAPEX факт", 13: "CAPEX", 14: "ИЗ_факт", 15: "Капзатраты", 16: "Capex_06" }],
["Дебиторка", { 0: "Дебиторка_итог", 1: "ДК_в_сальдо", 2: "Дебиторская", 3: "Д-ка_на_конец_мес", 4: "AR", 5: "Дебиторка_кон", 6: "ДК(кон.ост.)", 7: "Дебиторка_год", 8: "ДК факт", 9: "AR_06", 10: "Дебиторская", 11: "AR", 12: "ДК к/мес", 13: "AR", 14: "ДК_факт", 15: "Дебиторка_итого", 16: "AR_06" }],
["Кредиторка", { 0: "Кредиторка_итог", 1: "КК_в_сальдо", 2: "Кредиторская", 3: "К-ка_на_конец_мес", 4: "AP", 5: "Кредиторка_кон", 6: "КК(кон.ост.)", 7: "Кредиторка_год", 8: "КК факт", 9: "AP_06", 10: "Кредиторская", 11: "AP", 12: "КК к/мес", 13: "AP", 14: "КК_факт", 15: "Кредиторка_итого", 16: "AP_06" }],
["Численность", { 0: "Штат_ФТ", 1: "Числ._по_окладу", 2: "Численность", 3: "Штатное_число", 4: "Heads", 5: "Численность_кон", 6: "ФТ_кон.оот.", 7: "Численность_год", 8: "Штат факт", 9: "HC_06", 10: "Численность", 11: "FTE", 12: "Штат к/мес", 13: "HC", 14: "Числ_факт", 15: "Численность_итого", 16: "Headcount_06" }]
];
var LOGS = [
["10:02:14", "ok", "Получено 17 вложений из общего ящика Outlook"],
["10:02:15", "info", "Форматы: 17 Excel, 3 нестандартных шаблона"],
["10:02:18", "ok", "ООО А · сопоставлено 6 столбцов (шаблон 2024)"],
["10:02:21", "warn", "ООО Б · «Выручка_в_тыс» → «Выручка», множитель 1/1000"],
["10:02:23", "ok", "ООО В..И · автоматическое сопоставление (6/6)"],
["10:02:27", "warn", "ООО О · пустые строки в файле, пропущены"],
["10:02:29", "ok", "ООО Л..С · автоматическое сопоставление (6/6)"],
["10:02:31", "info", "1 расхождение единиц измерения, отклонения свыше 5% — 3 компании"]
];
var ANALYSIS = {
0: "Выручка 11 800 млн тг — 94% плана (−6%). EBITDA фактически выше плана (101%), операционная эффективность сохранена: CAPEX 510 млн тг при плане 420. Дебиторка +8%, кредиторка +3% — оборотный капитал в пределах нормы. Численность 1215 чел. при плане 1240.",
1: "Выручка 7 950 млн тг — 97% плана. Обнаружено расхождение единиц: в файле выручка в тысячах тенге, при переносе применён множитель 1/1000. EBITDA 94% плана, отклонение в пределах допустимого. Численность 842 чел.",
2: "Выручка 13 100 млн тг — −15% к плану, крупнейшее отклонение в группе. EBITDA 3 480 млн тг при плане 4 100 (−15%), доля в выручке снизилась с 27% до 27%. Дебиторка 1 720 при 880 — рост 96% требует разбора. Кредиторка 2 610 (96% плана).",
3: "Выручка 10 050 млн тг — 103% плана, опережение. EBITDA 102% плана. CAPEX 355 (104%). Дебиторка 480 (92% плана). Компенсация плановых отставок, численность 998 чел. при плане 1 010.",
4: "Выручка 10 900 млн тг — 96% плана. EBITDA 2 700 при 2 850 (95%). CAPEX 430 (110% плана) — опережение инвестиционной программы. Численность 1 128 чел.",
5: "Выручка 7 420 млн тг — 98% плана. EBITDA 1 830 (96%). Отклонения в пределах 5% по всем статьям. Численность 775 чел.",
6: "Выручка 14 350 млн тг — 103% плана, опережение. EBITDA 3 720 (103%). Дебиторка 730 (96% плана). Рост органический, численность 1 408 чел.",
7: "Выручка 6 510 млн тг — 97% плана. EBITDA 1 610 (96%). Отклонений свыше 5% нет. Численность 682 чел.",
8: "Выручка 9 980 млн тг — 96% плана, снижение 4% к плану. EBITDA 2 490 (94%). Кредиторка 1 565 (106% плана). Численность 1 035 чел.",
9: "Выручка 8 730 млн тг — 98% плана. EBITDA 2 210 (97%). Отклонения минимальные. Численность 908 чел.",
10: "Выручка 12 490 млн тг — 103% плана, опережение. EBITDA 3 310 (103%). CAPEX 415 (97%). Численность 1 258 чел.",
11: "Выручка 6 890 млн тг — 97% плана. EBITDA 1 720 (97%). Отклонений свыше 5% нет. Численность 740 чел.",
12: "Выручка 13 850 млн тг — 95% плана. EBITDA 3 640 (95%). Дебиторка 790 (95% плана), кредиторка 2 415 (104%). Численность 1 488 чел.",
13: "Выручка 8 910 млн тг — 96% плана. EBITDA 2 240 (94%). Дебиторка 480 (94%). Численность 958 чел.",
14: "Выручка 11 980 млн тг — 103% плана, опережение. EBITDA 3 080 (103%). Кредиторка 1 495 (95% плана). Численность 1 168 чел.",
15: "Выручка 8 160 млн тг — 97% плана. EBITDA 2 060 (96%). Отклонения в пределах 5%. Численность 830 чел.",
16: "Выручка 12 840 млн тг — 97% плана. EBITDA 3 280 (96%). Дебиторка 680 (96%). Численность 1 348 чел."
};
CO.forEach(function (c, i) { c.analysis = ANALYSIS[i]; c.aStatus = 0; });
CO[2].aStatus = 2; var A_ERR = CO[2];
var STEPS = [
{ id: "upload", n: 1, t: "Загрузка", sub: "распознавание файлов" },
{ id: "check", n: 2, t: "Проверка", sub: "данные и отклонения" },
{ id: "analysis", n: 3, t: "Черновик", sub: "анализа" },
{ id: "result", n: 4, t: "Итог", sub: "результат и отправка" }
];
/* ---------- utils ---------- */
var T = "light";
function $(id) { return document.getElementById(id); }
function esc(s) { return String(s).replace(/&/g, "&").replace(//g, ">").replace(/"/g, """); }
var NLC = new Intl.NumberFormat("ru-RU");
function fmt(n) { return n == null ? "—" : NLC.format(n); }
function pct(d) { if (!d) return "0"; return "−" + String(d).replace(".", ","); }
function pctSign(d) { return (d > 0 ? "+" : "−") + String(d).replace(".", ","); }
function ic(name) { return ''; }
function toast(msg, tone) {
var d = document.createElement("div");
d.className = "toast"; if (tone) d.setAttribute("data-tone", tone);
d.textContent = msg;
$("toasts").appendChild(d);
setTimeout(function () { d.style.transition = "opacity .3s"; d.style.opacity = "0"; setTimeout(function () { d.remove(); }, 320); }, 3600);
return true;
}
function sum(arr) { return arr.reduce(function (a, b) { return a + b; }, 0); }
function fileStatus(i) {
if (S.fileManual) return ["info", "Вручную"];
if (S.aiAccepted) return ["ok", "Сопоставлено"];
return S.fileStatus[i] || (i === 1 ? ["warn", "Единицы: ×1/1000"] : ["ok", "Сопоставлено"]);
}
/* ---------- shell ---------- */
function renderSidebar() {
var items = STEPS.map(function (st) {
var done = !!S.done[st.id]; var cur = S.screen === st.id;
return '';
});
items.push('');
$("sbNav").innerHTML = '
' + items.join("") + '
';
}
function renderTopbar() {
var t = "";
if (S.screen === "upload") t = "Загрузка и распознавание · " + "пятница, 10:02";
else if (S.screen === "check") t = "Проверка данных и отклонений";
else if (S.screen === "analysis") t = "Черновик анализа";
else if (S.screen === "result") t = "Итоговый результат";
else t = "О решении";
$("topTitle").innerHTML = '' + t + 'пакет на пн, 15:00';
}
function showScreen(id) {
if (id !== "about" && !canOpen(id)) { toast("Сначала завершите предыдущий шаг", "warn"); return; }
S.screen = id; save();
renderSidebar(); renderTopbar();
var r = { upload: viewUpload, check: viewCheck, analysis: viewAnalysis, result: viewResult, about: viewAbout }[id];
var el = $("view");
el.innerHTML = r();
el.scrollTop = 0;
document.querySelector(".kt-ai-main").scrollTop = 0;
bind(id);
closeMobile();
}
function canOpen(id) {
if (id === "upload") return true;
if (id === "check") return !!S.done.recognize;
if (id === "analysis") return !!S.done.check;
if (id === "result") return !!S.done.analysis || S.screen === "result";
return true;
}
function closeMobile() { var sb = $("sidebar"); if (sb) sb.removeAttribute("data-open"); $("scrim").classList.remove("on"); }
/* ---------- stepper ---------- */
function stepHtml(curId) {
var h = "";
STEPS.forEach(function (st, i) {
var done = !!S.done[st.id]; var cur = curId === st.id; var cls = [];
if (cur) cls.push('data-cur="true"');
if (done) cls.push('data-done="true"');
if (i > 0) h += '';
h += '' + (done ? ic("check") : st.n) + '' + st.t + '';
});
return '
' + h + '
';
}
/* ================= ЭКРАН 1 — загрузка ================= */
function viewUpload() {
var fileRows = FILES.map(function (f, i) {
var st = fileStatus(i);
return '
';
}
/* ================= ЭКРАН 2 — проверка ================= */
var chk = { company: "all", only: "all" };
function viewCheck() {
var opts = "" + CO.map(function (c, i) { return ""; }).join("");
var devs = CO.filter(function (c) { return c.maxDev > 5; }).length;
var kpis =
kpi("Компаний в сводном файле", "17 / 17", "план и факт, июнь") +
kpi("Отклонения плана > 5%", devs, "из 17 компаний") +
kpi("Единицы измерения", S.unitFixed.length ? "исправлено" : "1 / 17", "ООО Б · ×1/1000") +
kpi("Структура", "6 показателей", "итоговый лист + 17 вкладок");
return pageHead("Проверка данных и отклонения", "Сводный файл сформирован ИИ · проверьте единицы измерения и отклонения от плана",
'', '") +
stepHtml("check") +
'
' + kpis + '
' +
'
Сводная таблица
' +
'
' +
'' +
'' +
'' +
'
' +
'' +
'
Отклонения подсвечены: двухсегментная шкала — 2% и 5%. Строка с ошибками единиц помечена красным; исправление — по клику на ячейку. Итоговая строка — сумма по выбранным компаниям.
') +
"";
var note = $("fNote"); if (note) note.textContent = any ? totalN + " из 17 · план / факт, откл. в %" : "";
}
function pageHead(title, sub, left, right) {
return '
' + title + '
' + (sub || "") + '
' +
(right ? '
' + right + '
' : "") + '
';
}
/* ================= ЭКРАН 3 — черновик анализа ================= */
var curA = 0;
function analysisText(i) {
var o = S.analysis[i];
if (o && typeof o === "string") return o;
return CO[i].analysis;
}
function aStatus(i) { return (S.analysis[i] && S.analysis[i].status) || CO[i].aStatus || 0; }
function viewAnalysis() {
var list = CO.map(function (c, i) {
var st = aStatus(i);
var dot = st === 1 ? 'dot-ok' : (st === 2 ? 'dot-err' : 'dot-gen');
return '
На: финансовый директор · От: аналитик · Пн, 15:00
' +
'
Свод по дочерним компаниям, июнь
' +
'
По всем 17 компаниям факт к плану по выручке ' + (dV > 0 ? "−" + pctSign(dV) : pctSign(dV)) + "%, по EBITDA — " + pctSign(dE) + "% (млн тг). Единицы измерения 1 компании (ООО Б) исправлены и пересчитаны.
" +
memoRows +
'
Рекомендации: разобрать дебиторку ООО В (рост 96% к плану) и CAPEX ООО Д (110% к программе).
' +
'
' +
'
';
}
function analysisTextShort(c) {
var t = c.analysis;
return t.length > 200 ? t.slice(0, 197).replace(/\s+\S*$/, "") + "…" : t;
}
/* ================= действия ================= */
function setUnitFix(i, fixed) {
var idx = S.unitFixed.indexOf(1);
if (fixed && idx === -1) { S.unitFixed.push(1); }
if (!fixed) S.unitFixed = S.unitFixed.filter(function (x) { return x !== 1; });
save();
if (S.screen === "check") renderSumTable(); updateUnitBanner();
toast(fixed ? "Единицы ООО Б исправлены: ×1/1000 применён" : "Единицы ООО Б возвращены в исходные", fixed ? "ok" : "warn");
}
function updateUnitBanner() {
if (S.screen !== "check") return;
var banner = document.querySelector("#view .kt-ai-banner:not([data-tone='info']):not([data-tone='warn'])");
if (!banner) return;
var fixed = S.unitFixed.indexOf(1) !== -1;
banner.setAttribute("data-tone", fixed ? "ok" : "risk");
banner.innerHTML = fixed
? 'Единицы ООО Б исправлены: выручка переведена из тысяч в миллионы тенге.'
: 'Расхождение единиц: ООО Б. В файле выручка в тысячах тенге, в шаблоне — в миллионах. Клик по ячейке выручки — исправить вручную.';
var k = document.querySelectorAll(".kt-ai-kpi");
if (k[2]) k[2].querySelector(".value").textContent = fixed ? "исправлено" : "1 / 17";
}
function acceptAllAnalysis() {
CO.forEach(function (c, i) { S.analysis[i] = { status: 1 }; });
S.done.analysis = true; save();
toast("Черновик принят по всем 17 компаниям", "ok");
showScreen("analysis");
}
function makeMemo() {
if (!S.done.analysis) { toast("Сначала примите черновик анализа по всем компаниям", "warn"); return; }
showScreen("result");
toast("Записка сформирована", "ok");
}
function download(text, filename) {
try {
var b = new Blob([text], { type: "text/plain;charset=utf-8" });
var a = document.createElement("a");
a.href = URL.createObjectURL(b);
a.download = filename;
document.body.appendChild(a); a.click(); a.remove();
setTimeout(function () { URL.revokeObjectURL(a.href); }, 2000);
toast("Скачивание: " + filename, "ok");
} catch (e) { toast("Не удалось скачать файл", "warn"); }
}
function xlsxText() {
return "Сводный файл, июнь 2026, млн тг (дебиторка/кредиторка/численность — свои единицы)\n\nКомпания;Выручка (план);Выручка (факт);EBITDA (план);EBITDA (факт);CAPEX (план);CAPEX (факт);Дебиторка (план);Дебиторка (факт);Кредиторка (план);Кредиторка (факт);Численность (план);Численность (факт)\n" +
CO.map(function (c) { return [c.name, c.vp, c.vf, c.ep, c.ef, c.cap, c.caf, c.dp, c.df, c.cp, c.cf, c.hp, c.hf].join(";"); }).join("\n") +
"\n\n" + CO.map(function (c) { return "== " + c.name + " ==\n" + analysisText(CO.indexOf(c)); }).join("\n\n");
}
function memoText() {
var tv = totalRow(); var dV = dev({}, tv[2], tv[1]), dE = dev({}, tv[4], tv[3]);
return "ЗАПИСКА — свод по дочерним компаниям, июнь 2026\nНа: финансовый директор\n\nПо всем 17 компаниям факт к плану: выручка " + pctSign(dV) + "%, EBITDA " + pctSign(dE) + "% (млн тг).\nЕдиницы измерения ООО Б исправлены (тысячи → миллионы тенге).\n\n" + CO.filter(function (c) { return c.maxDev > 5 || c.name === "ООО Б"; }).map(function (c) { return "• " + c.name + ". " + analysisTextShort(c); }).join("\n") +
"\n\nРекомендации: разобрать дебиторку ООО В (рост 96% к плану) и CAPEX ООО Д (110% к программе).\n";
}
/* ---------- bind ---------- */
function bind(screen) {
var v = $("view");
v.querySelectorAll("[data-goto]").forEach(function (b) {
b.addEventListener("click", function () { showScreen(b.getAttribute("data-goto")); });
});
// загрузка
if (screen === "upload") {
v.querySelectorAll("[data-act='outlook']").forEach(function (b) { b.addEventListener("click", function () { toast("Обнаружено 17 вложений в общем ящике · загрузка завершена", "ok"); }); });
v.querySelectorAll("[data-act='recognize']").forEach(function (b) {
b.addEventListener("click", function () {
if (S.aiAccepted) { if (S.done.recognize) showScreen("check"); return; }
S.aiAccepted = true; S.done.recognize = true; save();
toast("Сопоставление завершено: 17/17 файлов, 1 расхождение единиц", "ok");
showScreen("upload");
});
});
v.querySelectorAll("[data-act='manual']").forEach(function (b) { b.addEventListener("click", function () {
S.fileManual = true; save(); toast("Открыт ручной режим для 1 файла. Проверьте столбцы и верните автоматический режим.", "warn"); showScreen("upload");
}); });
v.querySelectorAll("[data-file]").forEach(function (r) { r.addEventListener("click", function () { toast(esc(CO[+r.getAttribute("data-file")].name) + " · формат распознан, 6/6 столбцов", "ok"); }); });
}
// проверка
if (screen === "check") {
renderSumTable();
var fc = $("fCompany");
if (fc) { fc.value = chk.company; fc.addEventListener("change", function () { chk.company = fc.value; renderSumTable(); }); }
var fo = $("fOnly");
if (fo) fo.addEventListener("click", function (e) {
var b = e.target.closest(".seg"); if (!b) return;
chk.only = b.getAttribute("data-v");
fo.querySelectorAll(".seg").forEach(function (x) { x.setAttribute("data-active", x === b ? "true" : "false"); });
renderSumTable();
});
var box = $("sumTable");
if (box) box.addEventListener("click", function (e) {
var cell = e.target.closest("[data-unit]");
if (cell) { setUnitFix(1, S.unitFixed.indexOf(1) === -1); return; }
var tr = e.target.closest("tr[data-oi]");
if (tr) {
var i = +tr.getAttribute("data-oi");
toast(CO[i].name + ": " + (CO[i].maxDev > 2 ? "макс. отклонение " + CO[i].maxDev + "%" : "в пределах нормы") + (CO[i].name === "ООО Б" ? " · расхождение единиц: ×1/1000" : ""), CO[i].maxDev > 5 ? "warn" : "ok");
}
});
v.querySelectorAll("[data-act='to-check']").forEach(function (b) { b.addEventListener("click", function () {
if (S.unitFixed.indexOf(1) === -1) { toast("Сначала исправьте единицы ООО Б (клик по ячейке выручки)", "warn"); return; }
if (!S.done.check) { S.done.check = true; save(); }
showScreen("analysis");
}); });
}
// анализ
if (screen === "analysis") {
var ta = $("anaText"); if (ta) ta.value = analysisText(curA);
v.querySelectorAll("[data-ana]").forEach(function (r) { r.addEventListener("click", function () {
curA = +r.getAttribute("data-ana"); save(); showScreen("analysis");
}); });
if (ta) ta.addEventListener("input", function () {
var cur = S.analysis[curA] || {};
S.analysis[curA] = Object.assign(cur, { text: ta.value, edited: true });
save();
var st = ta.closest(".analysis-body").querySelector(".ed-stats");
if (st) st.textContent = ta.value.split(/\s+/).filter(Boolean).length + " слов";
});
v.querySelectorAll("[data-act='a-prev'],[data-act='a-next']").forEach(function (b) {
b.addEventListener("click", function () {
curA = (curA + (b.getAttribute("data-act") === "a-next" ? 1 : CO.length - 1)) % CO.length;
save(); showScreen("analysis");
});
});
v.querySelectorAll("[data-act='a-accept']").forEach(function (b) { b.addEventListener("click", function () {
var st = S.analysis[curA] || {}; st.status = 1; S.analysis[curA] = st; save();
toast(CO[curA].name + ": выводы приняты", "ok"); showScreen("analysis");
}); });
v.querySelectorAll("[data-act='accept-all']").forEach(function (b) { b.addEventListener("click", acceptAllAnalysis); });
v.querySelectorAll("[data-act='make-memo']").forEach(function (b) { b.addEventListener("click", makeMemo); });
}
// итог
if (screen === "result") {
v.querySelectorAll("[data-act='dl-xlsx']").forEach(function (b) { b.addEventListener("click", function () { download(xlsxText(), "Сводный_файл_июнь_2026.txt"); }); });
v.querySelectorAll("[data-act='dl-memo']").forEach(function (b) { b.addEventListener("click", function () { download(memoText(), "Записка_июнь_2026.txt"); }); });
var sb2 = v.querySelector("[data-act='send-pkg']");
if (sb2 && !S.sent) sb2.addEventListener("click", function () {
S.sent = true; S.done.result = true; save();
toast("Пакет отправлен финансовому директору · 09:58", "ok");
showScreen("result");
});
}
}
/* ---------- инициализация ---------- */
function init() {
var html = document.documentElement;
T = S.theme || "light";
html.setAttribute("data-theme", T);
var ti = $("themeIcon"); if (ti) ti.setAttribute("href", T === "light" ? "#moon" : "#sun");
$("themeToggle").addEventListener("click", function () {
T = T === "light" ? "dark" : "light";
S.theme = T; save();
html.setAttribute("data-theme", T);
if (ti) ti.setAttribute("href", T === "light" ? "#moon" : "#sun");
});
$("burger").hidden = window.innerWidth >= 832;
$("burger").addEventListener("click", function () {
var sb = $("sidebar");
var open = sb.hasAttribute("data-open");
if (open) closeMobile();
else { sb.setAttribute("data-open", "true"); $("scrim").classList.add("on"); }
$("burger").hidden = window.innerWidth >= 832;
});
$("scrim").addEventListener("click", closeMobile);
window.addEventListener("resize", function () { $("burger").hidden = window.innerWidth >= 832; });
document.querySelector(".kt-ai-shell").addEventListener("click", function (e) {
var n = e.target.closest(".kt-ai-nav-item[data-screen]");
if (n) showScreen(n.getAttribute("data-screen"));
});
if (S.resetFlag) { delete S.resetFlag; save(); toast("Предыдущее состояние не восстановилось · начат новый цикл", "warn"); }
renderSidebar();
showScreen(S.screen || "upload");
}
/* ================= ЭКРАН 5 — о решении ================= */
function viewAbout() {
return pageHead("О решении", "Сводный финансовый анализ дочерних компаний", "",
'') +
'
' +
card("Паспорт решения", dl([
["Наименование", "Сводный финансовый анализ дочерних компаний"],
["Исполнитель", "владелец процесса — сборка на платформе Vibe AI"],
["Пользователи", "аналитик, финансовый директор"],
["Частота", "еженедельно, вложения по пятницам"],
["Дедлайн", "понедельник, 15:00"]
])) +
card("Предпосылки", '
Ручная обработка данных 17 дочерних компаний занимает 3–4 часа в неделю
Разные форматы Excel приводят к путанице в столбцах и потере данных
') +
card("Входные данные", '
Выручка, EBITDA, CAPEX, дебиторка, кредиторка, численность — план и факт
Вложения в общем ящике Outlook, приходят по пятницам
У каждой компании свой шаблон листов и названий столбцов
') +
card("Что делает ИИ", '
Распознаёт формат файла и сопоставляет столбцы
Переносит данные в единый сводный файл
Подсвечивает отклонения от плана
Генерирует черновик анализа по каждой компании
') +
card("Что решает человек", '
Аналитик проверяет единицы измерения и расхождения
Аналитик редактирует и утверждает черновик анализа
Руководитель выборочно просматривает итоговый результат
') +
card("Результат и эффект", '
Сводный Excel: итоговый лист + листы по организациям