';
+ var best = hint[0];
+ var cands = hint.map(function (h, idx) {
+ return '
' + h.c + "
" +
+ '
' + esc(h.n) + "
" +
+ '' + h.conf + "%
";
+ }).join("");
+ return '
' + head +
+ '
Уверенность по первой подсказке' + best.conf + "%
" +
+ '
' + cands + "
" +
+ '
' +
+ '
';
+}
+
+function bindWork() {
+ var trs = document.querySelectorAll("#view .kt-ai-table tbody tr[data-id]");
+ for (var i = 0; i < trs.length; i++) {
+ trs[i].addEventListener("click", function () {
+ S.selected = this.getAttribute("data-id");
+ saveState(); renderWork();
+ });
+ }
+ var btns = document.querySelectorAll('#view [data-act]');
+ for (var j = 0; j < btns.length; j++) {
+ btns[j].addEventListener("click", onWorkAction);
+ }
+ var cands = document.querySelectorAll("#view .cand-row[data-cand]");
+ for (var c = 0; c < cands.length; c++) {
+ cands[c].addEventListener("click", function () {
+ var rows = document.querySelectorAll("#view .cand-row[data-cand]");
+ for (var k = 0; k < rows.length; k++) rows[k].classList.remove("sel");
+ this.classList.add("sel");
+ });
+ }
+}
+
+function onWorkAction(ev) {
+ var act = ev.currentTarget.getAttribute("data-act");
+ var r = (window.__allRequests || []).find(function (x) { return x.id === S.selected; });
+ if (!r) return;
+
+ if (act === "confirm") {
+ var code = r.trr;
+ if (r.hints && r.hints.length) {
+ var selCand = document.querySelector("#view .cand-row.sel");
+ var ci = 0;
+ if (selCand) {
+ var ciRaw = parseInt(selCand.getAttribute("data-cand"), 10);
+ ci = !isNaN(ciRaw) ? ciRaw : 0;
+ if (ci >= r.hints.length) ci = 0;
+ }
+ var picked = r.hints[ci];
+ if (picked) code = picked.c;
+ }
+ apiPatch("/api/requests", { id: r.id, codeTru: true, trr: code })
+ .then(function () {
+ toast("Код " + code + " подтверждён, реестр обновлён", "ok");
+ return refresh();
+ })
+ .catch(function (e) { toast("Ошибка: " + e.message, "err"); });
+ } else if (act === "return") {
+ apiPatch("/api/requests", { id: r.id, st: "rejected", done: true, who: "закупщик" })
+ .then(function () {
+ S.selected = nextIn((window.__allRequests || []).filter(function (x) { return x.st === "new" || x.st === "checking"; }), r.id);
+ saveState();
+ toast(r.id + " возвращена инициатору", "warn");
+ return refresh();
+ })
+ .catch(function (e) { toast("Ошибка: " + e.message, "err"); });
+ } else if (act === "dispute") {
+ modalOpen("Спорный случай",
+ '
Заявка ' + r.id + " будет передана руководителю для разбора: ИИ предложил код, который не совпадает с версией в заявке. Решение по ней примет руководитель.
" + (rows || emptyRow("Ничего не найдено", "Снимите фильтры — реестр за месяц заполнен.")) + "
" +
+ '
Заявки по неделям сентября
' +
+ '
' + bars + "
" +
+ '
' +
+ 'входящие' +
+ 'высокая нагрузка
' +
+ "
Что показывает реестр" +
+ "Пик нагрузки — 2–7 сентября: 10–13 заявок в день совпали с закрытием планового цикла. Возвратов в сентябре немного, большинство возвратов — дубли уже приобретённых услуг.
" +
+ "
";
+ document.getElementById("view").innerHTML = html;
+ bindRegistry();
+}
+
+function inputSearch() {
+ return '';
+}
+
+function selStatus() {
+ var opts = "";
+ for (var k in STATUS) {
+ if (!Object.prototype.hasOwnProperty.call(STATUS, k)) continue;
+ opts += '";
+ }
+ return '";
+}
+
+function selSrc() {
+ return '";
+}
+
+function bindRegistry() {
+ var trs = document.querySelectorAll("#view .kt-ai-table tbody tr[data-id]");
+ for (var i = 0; i < trs.length; i++) {
+ trs[i].addEventListener("click", function () {
+ S.selected = this.getAttribute("data-id");
+ S.screen = "approve"; S.regRole = "legal";
+ saveState(); render();
+ });
+ }
+ var q = document.querySelector(".reg-q");
+ if (q) q.addEventListener("input", function () { S.regQuery = this.value; saveState(); renderRegistry(); });
+ var status = document.querySelector(".reg-status");
+ if (status) status.addEventListener("change", function () { S.regStatus = this.value; saveState(); renderRegistry(); });
+ var src = document.querySelector(".reg-src");
+ if (src) src.addEventListener("change", function () { S.regSrc = this.value; saveState(); renderRegistry(); });
+ var exp = document.querySelector('#view [data-act="csv"]');
+ if (exp) exp.addEventListener("click", exportCsv);
+}
+
+function exportCsv() {
+ window.location.href = "/api/export.csv";
+ toast("Реестр выгружен в CSV", "ok");
+}
+
+// ================= СОГЛАСОВАНИЕ =================
+function renderApprove() {
+ var role = S.regRole || "legal";
+ var list = window.__allRequests || [];
+ var pool = list.filter(function (r) { return role === "legal" ? r.st === "toLegal" : r.st === "toSign"; });
+ pool.sort(function (a, b) { return a.in < b.in ? 1 : -1; });
+
+ var sel = null;
+ for (var i = 0; i < pool.length; i++) { if (pool[i].id === S.selected) { sel = pool[i]; break; } }
+ var isDisputed = role === "boss" && sel && sel.st === "disputed";
+ if (!sel && pool.length) { sel = pool[0]; }
+
+ var rows = pool.map(function (r) {
+ var sAttr = r.id === S.selected ? ' data-selected="true"' : "";
+ return '
' +
+ p("Заявки на закупку поступают из 1С и письмами, около 150 в месяц.") +
+ p("Процесс включает ручную проверку данных (код ТРУ, план, сумма) и последовательную передачу между участниками.") +
+ "
" +
+
+ '
Входные данные и источники
' +
+ '
' +
+ p("Заявки из 1С и электронной почты.") +
+ p("Реестр в Excel: номер, инициатор, сумма, статус, даты.") +
+ "
" +
+
+ '
Процессы для внедрения ИИ
' +
+ '
' +
+ p("Проверка по чек-листу.") +
+ p("Подсказка кода ТРУ.") +
+ p("Ведение реестра и напоминания.") +
+ "
"; }
+
+function steps() {
+ var steps = [
+ "Поступление заявки из 1С или по электронной почте",
+ "Закупщик проверяет код ТРУ, наличие в плане и сумму",
+ "ИИ подсказывает код ТРУ и ведёт реестр",
+ "Закупщик возвращает заявку инициатору при ошибке",
+ "Передача заявки юристу для согласования",
+ "Руководитель подписывает заявку",
+ "Закупщик отправляет заявку в 1С и уведомляет инициатора"
+ ];
+ return '
' + steps.map(function (s, i) {
+ return '
' + (i + 1) + '
' + esc(s) + "
";
+ }).join("") + "
";
+}
+
+function passSteps() {
+ var ai = ["ИИ подсказывает код ТРУ", "ИИ ведёт реестр", "ИИ обновляет статусы и даты"];
+ var hum = ["Закупщик проверяет код ТРУ, план и сумму", "Закупщик решает, вернуть ли заявку", "Юрист согласовывает", "Руководитель подписывает", "Руководитель разбирает спорные случаи"];
+ return '
Кто делает что
' +
+ '
' +
+ '
' +
+ '
ИИ
' +
+ ai.map(function (s) { return '
·
' + esc(s) + "
"; }).join("") +
+ "
" +
+ '
' +
+ '
Человек
' +
+ hum.map(function (s) { return '
·
' + esc(s) + "
"; }).join("") +
+ "
";
+}
+
+function risks() {
+ return '
Контроль и риски
' +
+ '
' +
+ riskItem("Ошибка ИИ в коде ТРУ", "ИИ может ошибаться в коде ТРУ — все коды подтверждает закупщик.") +
+ riskItem("Дубли", "ИИ может пропустить дубли — закупщик проверяет дубли перед отправкой в 1С.") +
+ riskItem("Спорные случаи", "Спорные случаи разбирает руководитель, решение фиксируется в реестре.") +
+ "
" +
+ '
' +
+ '
' +
+ '
~3 000 чэкономия в месяц150 заявок × 20 ч — оценка владельца процесса
' +
+ '
~150заявок в месяциз 1С и по почте
' +
+ '
2 ролиюрист и руководительпроверяют после закупщика
' +
+ "
" +
+ '
' +
+ 'Результат' +
+ p("Реестр и статус заявки для закупщика и руководителя: меньше времени на обработку и меньше ошибок в кодах ТРУ.") +
+ 'Ожидаемый эффект' +
+ p("Быстрая обработка заявок, меньше ошибок в кодах ТРУ.") +
+ 'Экономический эффект' +
+ p("Около 3 000 ч в месяц (150 заявок × 20 ч) — оценка владельца процесса.") +
+ 'Формат реализации' +
+ p("Веб-интерфейс на Vibe AI: сначала статичный макет, после согласования — рабочее решение.") +
+ "