"use strict";
/* Экспертиза документов для советов — статичный прототип, состояние в localStorage. */
var LS_KEY = "edds-v1";
function $(id) { return document.getElementById(id); }
function esc(s) {
return String(s == null ? "" : s).replace(/[&<>"']/g, function (c) {
return { "&": "&", "<": "<", ">": ">", '"': """, "'": "'" }[c];
});
}
function escJs(s) { return esc(String(s == null ? "" : s).replace(/\\/g, "\\\\").replace(/'/g, "\\'")); }
var ST = {
wait: { label: "Ожидает проверки", tone: "warn" },
ready: { label: "Готово к анализу", tone: "ok" },
process: { label: "Процесс отбора", tone: "info" },
qual: { label: "Квалификация", tone: "info" },
contra: { label: "Противоречие", tone: "risk" },
checked: { label: "На проверке", tone: "info" },
conf: { label: "Подтверждено", tone: "ok" },
falsep: { label: "Ложное срабатывание", tone: "muted" },
draft: { label: "Черновик", tone: "warn" },
sent: { label: "Готово к согласованию", tone: "info" },
agree: { label: "Согласовано", tone: "ok" },
decl: { label: "Отклонено", tone: "risk" },
pending: { label: "Ожидает решения", tone: "warn" }
};
function pill(key, label) {
var st = ST[key] || { label: label || key, tone: "muted" };
return '' + esc(st.label) + "";
}
function num(s) { return '' + s + ""; }
function icon(name) { return ''; }
/* ---------- Демо-данные ---------- */
function seed() {
return {
view: "upload",
req: "Заявка ЭД-2026-118 · Управление сетевых сервисов · 14.09.2026",
candidate: "А. Т. Нурмолдаев",
sources: [
{ n: "Трудовой кодекс Республики Казахстан", s: "Законодательство", d: 207, u: 1 },
{ n: "Закон Республики Казахстан «Об акционерных обществах»", s: "Законодательство", d: 148, u: 1 },
{ n: "Правила трудового распорядка", s: "Внутренние документы", d: 12, u: 1 },
{ n: "Правила поиска и подбора персонала", s: "Внутренние документы", d: 8, u: 1 },
{ n: "Корпоративный стандарт по управлению человеческими ресурсами фонда", s: "Внутренние документы", d: 96, u: 1 },
{ n: "Должностная инструкция SEO-1 (управление сетевыми сервисами)", s: "Внутренние документы", d: 14, u: 1 },
{ n: "Положение о совещаниях и комиссиях фонда", s: "Внутренние документы", d: 22, u: 1 }
],
files: [],
progress: null,
dropActive: false,
running: false,
contra: false,
falseDone: false,
log: [],
violations: [],
checklist: [],
verdict: "",
status: "draft",
rejected: null,
stamp: null
};
}
var D = null;
function load() {
try { var raw = localStorage.getItem(LS_KEY); D = raw ? JSON.parse(raw) : seed(); }
catch (e) { D = seed(); }
if (!D.files || !D.violations) D = seed();
}
function save() {
try { localStorage.setItem(LS_KEY, JSON.stringify(D)); } catch (e) {}
}
/* ---------- Прогресс процесса ---------- */
function allFilesReady() {
for (var i = 0; i < D.files.length; i++) if (D.files[i].s !== "ready") return false;
return true;
}
function doneCount() {
var n = 0, i;
for (i = 0; i < D.violations.length; i++) if (D.violations[i].v === "conf") n++;
return n;
}
function stepNum() {
if (D.view === "upload") return allFilesReady() ? 2 : 1;
if (D.view === "results") return 2;
if (D.view === "verdict") return 3;
if (D.view === "approve") return D.status === "agree" || D.status === "decl" ? 5 : 4;
return 1;
}
var STEPS = ["Загрузка", "Анализ", "Заключение", "Согласование"];
/* ---------- UI: тосты, модалки ---------- */
var S = {};
function toast(msg, tone) {
var box = $("toasts");
if (!box) return;
var el = document.createElement("div");
el.className = "kt-ai-toast";
if (tone) el.dataset.tone = tone;
el.textContent = msg;
box.appendChild(el);
setTimeout(function () {
el.style.transition = "opacity .3s, transform .3s";
el.style.opacity = "0";
el.style.transform = "translateY(6px)";
setTimeout(function () { if (el.parentNode) el.parentNode.removeChild(el); }, 320);
}, 2600);
}
function openModal(html) { var m = $("modal"); m.innerHTML = html; m.style.display = "flex"; }
function closeModal() { var m = $("modal"); m.style.display = "none"; m.innerHTML = ""; }
S.closeModal = closeModal;
function openDrawer(html) { var d = $("drawer"); d.innerHTML = html; d.style.display = "block"; }
function closeDrawer() { var d = $("drawer"); d.style.display = "none"; d.innerHTML = ""; }
/* ---------- Навигация и рендер ---------- */
var NAV = [
{ id: "upload", label: "Загрузка и обзор", icon: "upload" },
{ id: "results", label: "Результаты анализа", icon: "sparkles" },
{ id: "verdict", label: "Формирование заключения", icon: "pencil" },
{ id: "approve", label: "Согласование", icon: "check-circle" },
{ id: "about", label: "О решении", icon: "info", group: "Решение" }
];
var TITLES = {
upload: "Загрузка и обзор материалов",
results: "Результаты анализа ИИ",
verdict: "Формирование заключения",
approve: "Согласование руководителем",
about: "О решении"
};
var SUBS = {
upload: "Пакет документов · первичное ознакомление",
results: "Сверка процесса · проверка квалификации",
verdict: "Верификация выводов · итоговый документ",
approve: "Итоговое заключение · решение руководителя",
about: "Паспорт ИИ-решения"
};
function renderNav() {
var nav = $("nav");
if (!nav) return;
var group = null, html = "";
for (var i = 0; i < NAV.length; i++) {
var n = NAV[i];
if (n.group && n.group !== group) {
html += '
' + esc(n.group) + "
";
group = n.group;
}
if (!n.group) group = null;
var active = D.view === n.id ? ' data-active="true"' : "";
html += '
' +
'' + esc(n.label) + "
";
(function (id) {
nav.lastChild.onclick = function () { S.go(id); };
})(n.id);
}
var sb = $("sbReq");
if (sb) sb.innerHTML = '
Текущая заявка
' + esc(D.req) + "
";
}
function render() {
var html;
if (D.view === "upload") html = vUpload();
else if (D.view === "results") html = vResults();
else if (D.view === "verdict") html = vVerdict();
else if (D.view === "approve") html = vApprove();
else html = vAbout();
var view = $("viewInner");
if (!view) view = $("view");
if (!view) return;
view.innerHTML = html;
$("pageTitle").textContent = TITLES[D.view] || "";
$("pageSub").textContent = SUBS[D.view] || "";
$("roleChip").textContent = (D.view === "approve") ? "Руководитель" : "Эксперт";
renderNav();
save();
}
function vStepper() {
var cur = stepNum();
var html = '
';
for (var i = 0; i < STEPS.length; i++) {
var st = i + 1 < cur ? "done" : (i + 1 === cur ? "current" : "");
var n = i + 1 < cur ? "✓" : String(i + 1);
html += '
' + n + "" + esc(STEPS[i]) + "
";
if (i < STEPS.length - 1) html += '';
}
return html + "
Загрузите документы: перетащите файлы в зону загрузки или нажмите «выберите на устройстве». Система определит тип каждого файла, " +
"отметит готовность и после полной загрузки пакета включит кнопку «Запустить анализ ИИ». Анализ будет идти по фактическим загруженным файлам — " +
"сверка с внутренними правилами и законодательством по 20 источникам.
";
}
function dropZoneHtml() {
var active = D.dropActive ? ' data-active="true"' : "";
return '
";
}).join("");
var logRows = D.log.map(function (l) {
return '
' + esc(l.t) + '' + esc(l.b) + "
";
}).join("");
var nextOk = true;
for (var k = 0; k < D.violations.length; k++) if (D.violations[k].v === "checked") nextOk = false;
var next = "";
if (nextOk) {
next = '
' +
'' +
'
';
}
return kpis + banner +
'
Несогласованности
' +
'
' +
'
Ссылка на пункт
Нарушение
Тип
Статус
Действие
' +
"" + rows + "
" + next + "" +
'
Журнал действия ИИ' +
'10:42 — 10:46
' +
'
' + logRows + "
" +
'
Что показывает анализ
' +
"
Система сверяет процесс отбора с внутренними документами и законодательством, затем проверяет квалификацию кандидата по должностной инструкции. " +
"Каждый вывод ссылается на пункт нормативного акта — эксперт проверяет ссылки и при необходимости отмечает ложные срабатывания.
";
}
function runScreen() {
var steps = [
"Извлечение текста из пакета документов",
"Сверка с законодательством и внутренними документами",
"Проверка квалификации кандидата",
"Формирование вывода"
];
var rows = steps.map(function (s, i) {
return '
Анализ занимает обычно 3–5 минут. Можно закрыть вкладку — прогресс сохранится.
";
}
var stepsTime = ["10:46", "10:46", "10:46", "10:46"];
/* ---------- Экран 3. Формирование заключения ---------- */
function vVerdict() {
var checks = D.checklist.map(function (idx) {
var v = D.violations[idx];
if (!v) return "";
return '";
}).join("");
var sent = D.status === "sent";
var status = sent ? pill("sent") : pill("draft");
var docText = $("docText") && $("docText").textContent ? $("docText").textContent : D.verdict;
if (docText !== D.verdict) D.verdict = docText;
return vStepper() +
'
' +
'Ожидает решения руководителя' +
'Проверены материалы на назначение руководителя SEO-1 · ' + num("14.09.2026") + "
";
btns = '
' +
'' +
'
';
}
var checks = D.checklist.map(function (idx) {
var v = D.violations[idx];
if (!v) return "";
return '
✓' + esc(v.d) + ' ' + esc(v.r) + "
";
}).join("");
return kpis + banner +
'
Итоговое заключение
' +
'
' +
'
ЗАКЛЮЧЕНИЕпо заявке ЭД-2026-118 · SEO-1, управление сетевых сервисов
' +
'
' + esc(D.verdict) + "
" +
'
Подтвержденные нарушения
' +
'
' + checks + "
" +
btns;
}
/* ---------- Экран 5. О решении ---------- */
function vAbout() {
return '
О решении
' +
'
' +
'НаименованиеЭкспертиза документов для советов
' +
'ИсполнительВладелец процесса — сборка на платформе Vibe AI
' +
'ПользовательЭксперт, руководитель
' +
'Дата внедрения—
' +
'
' +
passCard("Предпосылки", "
Необходимость читать большое количество внутренних документов и законодательных актов
Необходимость сравнивать документы на соответствие нормативным требованиям
") +
passCard("Входные данные и источники", "
Трудовой кодекс Республики Казахстан
Закон «Об акционерных обществах»
Правила трудового распорядка
Правила поиска и подбора персонала
Корпоративный стандарт по управлению человеческими ресурсами фонда
") +
passCard("Процессы для внедрения ИИ", "
Сверка пояснительной записки с фактическим процессом отбора
Проверка соответствия кандидата квалификационным требованиям
Поиск несоответствий и противоречий в документах
") +
passCard("Результат", "
Согласование документов со списком нарушений и ссылками на пункты законов и внутренних документов
Заключение со списком нарушений и ссылками на пункты законов и внутренних документов
") +
passCard("Ожидаемый эффект", "
Сокращение времени рассмотрения материалов
Повышение качества проверки за счёт снижения риска человеческих ошибок
") +
passCard("Экономический эффект", "
Объём20 экспертиз в месяц во всех экспертах
Высвобождение50 часов в месяц (оценка Төре)
") +
passCard("Контроль и риски", "
Возможность ошибки ИИ при противоречиях в разных внутренних документах
Необходимость проверки выводов экспертом
") +
passCard("Меры по снижению", "
Проверка результата человеком перед использованием
Журнал действий ИИ и возможность вернуться в ручной режим
") +
passCard("Формат реализации", "
ИИ-агент на платформе Alem; при необходимости — простой веб-экран на Vibe AI
Экраны макета: Загрузка и обзор; Результаты анализа; Формирование заключения; Согласование руководителем
") +
"
" +
'
Путь сотрудника
' +
"
Эксперт загружает документы на экране «Загрузка и обзор материалов», переходит на «Результаты анализа ИИ» и проверяет выводы, " +
"формировает итоговое заключение на «Формировании заключения», руководитель просматривает и согласует документы на «Согласовании у руководителя».
";
}
function passCard(title, body) {
return '
' + esc(title) + "
" + body + "
";
}
function nowTime() {
var d = new Date();
function p(x) { return (x < 10 ? "0" : "") + x; }
return p(d.getHours()) + ":" + p(d.getMinutes());
}
/* ---------- Действия ---------- */
var STEPS_UPLOAD = [
"Проверка файла",
"Сканирование на вирусы",
"Извлечение текста"
];
/* Скрытый input для выбора файлов на устройстве */
if (typeof window !== "undefined") {
var _fileInput = null;
function getFileInput() {
if (!_fileInput) {
_fileInput = document.createElement("input");
_fileInput.type = "file";
_fileInput.multiple = true;
_fileInput.accept = ".pdf,.docx,.doc,.xlsx,.xls,.csv,.txt";
_fileInput.style.display = "none";
_fileInput.addEventListener("change", function () {
if (_fileInput.files && _fileInput.files.length) {
handleFiles(Array.prototype.slice.call(_fileInput.files));
}
_fileInput.value = "";
});
document.body.appendChild(_fileInput);
}
return _fileInput;
}
window.__getFileInput = getFileInput;
}
function handleFiles(arr) {
if (!arr || !arr.length) return;
var existing = {};
for (var k = 0; k < D.files.length; k++) existing[D.files[k].n] = true;
var toAdd = [];
for (var i = 0; i < arr.length; i++) {
var f = arr[i];
if (existing[f.name]) continue;
toAdd.push({ f: f, t: classifyFile(f.name), size: f.size, d: nowTime() + " · " + nowTime() });
}
if (!toAdd.length) { toast("Файлы уже загружены", "warn"); return; }
var total = 0;
for (var j = 0; j < toAdd.length; j++) total += toAdd[j].size;
D.progress = { active: true, step: 0, pct: 0, file: toAdd[0].f.name, size: total, done: {} };
D.files = [];
save();
render();
simulateUpload(toAdd, 0, total);
}
function simulateUpload(list, idx, total) {
if (idx >= list.length) {
if (typeof _uploadTimer !== "undefined" && _uploadTimer) clearInterval(_uploadTimer);
D.progress = null;
save();
toast(D.files.length + " файл(ов) загружено в пакет", "ok");
return;
}
var item = list[idx];
var name = item.f.name;
var size = item.size;
var step = 0;
var pct = 0;
D.progress = { active: true, step: 0, pct: 0, file: name, size: total };
save();
render();
var iv = setInterval(function () {
pct += 8 + Math.floor(Math.random() * 10);
if (pct >= 100) pct = 100;
step = pct < 34 ? 0 : (pct < 67 ? 1 : 2);
D.progress = { active: true, step: step, pct: pct, file: name, size: total };
save();
render();
if (pct >= 100) {
clearInterval(iv);
setTimeout(function () {
D.files.push({ n: name, t: item.t, size: size, d: item.d, s: "ready" });
save();
render();
setTimeout(function () {
simulateUpload(list, idx + 1, total);
}, 700);
}, 400);
}
}, 140);
}
S.delFile = function (i) {
D.files.splice(i, 1);
save();
render();
toast("Файл удалён из пакета", "info");
};
S.fileReady = function (i) {
D.files[i].s = "ready";
render();
toast("Файл отмечен как готовый к анализу", "ok");
};
S.go = function (id) { D.view = id; render(); };
function genViolations() {
var base = [];
for (var i = 0; i < D.files.length; i++) {
var f = D.files[i];
base.push(
{ d: f.n + ": текст извлечён и сверен с внутренними документами", y: "process", r: f.t + ", раздел 1", v: "checked" },
{ d: f.n + ": найдено 2 несоответствия с нормативной базой", y: "qual", r: f.t + ", ст. 36", v: "checked" }
);
}
base.push(
{ d: "Протокол: решение голосованием 4:1, правила — единогласно", y: "contra", r: "ТК РК, ст. 165", v: "falsep" }
);
if (base.length === 1) {
base.unshift({ d: "Пакет пуст — нет данных для полного анализа", y: "process", r: "—", v: "falsep" });
}
return base;
}
S.analyze = function () {
if (!D.files.length) { toast("Сначала загрузите файлы", "warn"); return; }
if (D.files.some(function (f) { return f.s !== "ready"; })) { toast("Дождитесь завершения загрузки всех файлов", "warn"); return; }
D.running = true;
D.contra = false;
D.falseDone = false;
var vio = genViolations();
D.checklist = [];
for (var k = 0; k < vio.length; k++) {
vio[k].v = "checked";
D.checklist.push(k);
}
D.status = "draft";
D.rejected = null;
D.stamp = null;
D.violations = vio;
D.verdict = "Заявка на назначение руководителя уровня SEO-1, управление сетевых сервисов (кандидат " + esc(D.candidate) + ") прошла проверку соответствия нормативной базе. Итоговое заключение будет сформировано после экспертной проверки выводов.";
D.log = [];
save();
render();
startLogStream();
setTimeout(function () {
if (!D.running) return;
for (var m = 0; m < D.violations.length; m++) if (D.violations[m].y === "contra") D.violations[m].v = "falsep";
D.running = false;
D.contra = true;
var proc = 0, qual = 0, contra = 0;
for (var n = 0; n < D.violations.length; n++) {
var y = D.violations[n].y;
if (y === "process") proc++;
else if (y === "qual") qual++;
else if (y === "contra") contra++;
}
D.log.push({ t: nowTime(), b: "Обнаружено несоответствий: " + (proc + qual) + ", противоречий: " + contra });
D.log.push({ t: nowTime(), b: "Журнал завершён — выводы переданы эксперту" });
D.view = "results";
save();
render();
toast("Анализ завершён — переход в результаты", "ok");
}, 6000);
};
function genLogPlan() {
var plan = [];
var files = D.files.concat([]);
for (var i = 0; i < files.length; i++) {
plan.push({ b: "Извлечение текста: " + files[i].n });
}
plan.push({ b: "Сверка с Правилами поиска и подбора персонала, п. 4.2" });
plan.push({ b: "Сверка с Законом «Об АО», ст. 36" });
plan.push({ b: "Проверка квалификации кандидата: стаж, образование, аттестация" });
return plan.map(function (line) { return { t: nowTime(), b: line.b }; });
}
function startLogStream() {
var plan = genLogPlan();
var delay = 300;
for (var i = 0; i < plan.length; i++) (function (line) {
setTimeout(function () {
if (D.running) {
D.log.push(line);
save();
render();
}
}, delay);
})(plan[i]);
}
S.closeDrawer = closeDrawer;
S.viewFile = function (i) {
var f = D.files[i];
openDrawer(
'
' +
"" + esc(f.n) + "" + pill(f.s) +
'
" +
'
' +
'
' + esc(f.t) + '' + esc(f.d) + "
" +
'
' +
"
Документ загружен во внутреннюю систему. Эксперт просматривает комплектность и при необходимости открывает исходник в корпоративном хранилище.