v1.1: реестр — столбец «Срок, дней» (amber >2 дн.) + фильтр по статусу в тулбаре; фильтры по чипам убраны

This commit is contained in:
tore 2026-09-22 18:19:43 +00:00
parent 8613a2d6ef
commit f1abbd96e4
2 changed files with 28 additions and 26 deletions

View File

@ -103,6 +103,11 @@ function saveState() {
try { localStorage.setItem(LS_KEY, JSON.stringify(S)); } catch (e) {}
}
function daysIn(id) {
var d = { "ЗК-0918": 2, "ЗК-0919": 1, "ЗК-0920": 1, "ЗК-0916": 2, "ЗК-0915": 2, "ЗК-0917": 4, "ЗК-0914": 3, "ЗК-0909": 8 };
return d[id] || 1;
}
function byId(id) {
for (var i = 0; i < BASE_REQUESTS.length; i++) {
if (BASE_REQUESTS[i].id === id) return BASE_REQUESTS[i];
@ -429,30 +434,16 @@ function renderRegistry() {
var sumWork = 0;
list.forEach(function (r) { if (["new", "checking"].indexOf(r.st) >= 0) sumWork += r.sum; });
var chips =
chipOn("all", "Все", list.length) +
chipOn("new", "Новые", countSt("new")) +
chipOn("checking", "Проверка", countSt("checking")) +
chipOn("toLegal", "Согласование", countSt("toLegal")) +
chipOn("toSign", "Подписание", countSt("toSign")) +
chipOn("disputed", "Спорные", countSt("disputed")) +
chipOn("sent", "В 1С", done) +
chipOn("rejected", "Возврат", rej);
function countSt(x) { return list.filter(function (r) { return r.st === x; }).length; }
function chipOn(val, label, n) {
return '<span class="kt-ai-filter-chip' + (st === val ? ' data-active="true"' : "") + '" data-st="' + val + '">' + esc(label) +
' <span class="kt-ai-num">' + n + "</span></span>";
}
var rows = filtered.map(function (r) {
var srcIc = r.src === "1С" ? "spreadsheet" : "mail";
var disp = r.done ? r.done : "—";
var di = daysIn(r.id);
return '<tr data-id="' + r.id + '"><td class="kt-ai-t-medium">' + r.id + "</td>" +
"<td>" + esc(r.init) + "</td>" +
'<td class="num kt-ai-num">' + fmtSum(r.sum) + "</td>" +
"<td>" + statusChip(r.st) + "</td>" +
'<td class="num kt-ai-num' + (di > 2 ? " sl-amber" : "") + '">' + di + "</td>" +
"<td class=\"kt-ai-num\">" + r.in + "</td>" +
'<td class="kt-ai-num">' + disp + "</td>" +
'<td><span class="src-cell"><svg class="kt-icon kt-icon-sm" aria-hidden="true"><use href="#' + srcIc + '"></use></svg>' + r.src + "</span></td></tr>";
@ -476,12 +467,12 @@ function renderRegistry() {
'<div class="kt-ai-toolbar"><div class="kt-ai-filterbar">' +
inputSearch() +
'<span class="kt-ai-spacer"></span>' +
selStatus() +
selSrc() +
'<button class="kt-ai-btn" data-act="csv"><svg class="kt-icon" aria-hidden="true"><use href="#download"></use></svg>Экспорт</button>' +
"</div></div>" +
'<div class="kt-ai-filterbar reg-st-chips">' + chips + "</div>" +
'<div class="kt-ai-table-wrap"><table class="kt-ai-table"><thead><tr>' +
"<th>Номер</th><th>Инициатор</th><th class=\"num\">Сумма</th><th>Статус</th><th>Поступила</th><th>Обработана</th><th>Источник</th>" +
"<th>Номер</th><th>Инициатор</th><th class=\"num\">Сумма</th><th>Статус</th><th class=\"num\">Срок, дней</th><th>Поступила</th><th>Обработана</th><th>Источник</th>" +
"</tr></thead><tbody>" + (rows || emptyRow("Ничего не найдено", "Снимите фильтры — реестр за месяц заполнен.")) + "</tbody></table></div>" +
'<div class="chart-card"><div class="kt-ai-h3">Заявки по неделям сентября</div>' +
'<div class="cc-bars">' + bars + "</div>" +
@ -499,6 +490,18 @@ function inputSearch() {
return '<input class="kt-ai-input reg-q" type="text" placeholder="Номер, инициатор, предмет…" value="' + esc(S.regQuery || "") + '" style="max-width:240px;height:32px">';
}
function selStatus() {
var opts = "";
for (var k in STATUS) {
if (!Object.prototype.hasOwnProperty.call(STATUS, k)) continue;
opts += '<option value="' + k + '"' + (S.regStatus === k ? " selected" : "") + ">" + STATUS[k].label + "</option>";
}
return '<div class="kt-ai-select-wrap" style="width:auto"><select class="kt-ai-select reg-status" style="height:32px">' +
'<option value="all"' + (S.regStatus === "all" ? " selected" : "") + ">Все статусы</option>" +
opts +
"</select></div>";
}
function selSrc() {
return '<div class="kt-ai-select-wrap" style="width:auto"><select class="kt-ai-select reg-src" style="height:32px">' +
'<option value="all"' + (S.regSrc === "all" ? " selected" : "") + ">Все источники</option>" +
@ -517,23 +520,19 @@ function bindRegistry() {
}
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 chips = document.querySelectorAll("#view .reg-st-chips .kt-ai-filter-chip");
for (var c = 0; c < chips.length; c++) {
chips[c].addEventListener("click", function () {
S.regStatus = this.getAttribute("data-st"); saveState(); renderRegistry();
});
}
var exp = document.querySelector('#view [data-act="csv"]');
if (exp) exp.addEventListener("click", exportCsv);
}
function exportCsv() {
var list = allLive();
var head = "Номер;Инициатор;Сумма;Статус;Поступила;Обработана;Источник;Предмет\n";
var head = "Номер;Инициатор;Сумма;Статус;Срок (дней);Поступила;Обработана;Источник;Предмет\n";
var body = list.map(function (r) {
var parts = [r.id, r.init, r.sum, STATUS[r.st].label, r.in, r.done || "", r.src, '"' + esc(r.subj) + '"'];
var parts = [r.id, r.init, r.sum, STATUS[r.st].label, daysIn(r.id), r.in, r.done || "", r.src, '"' + esc(r.subj) + '"'];
return parts.join(";");
}).join("\n");
var blob = new Blob(["\uFEFF" + head + body], { type: "text/csv;charset=utf-8" });

View File

@ -48,6 +48,9 @@
/* Строка источника в таблице */
.src-cell { display: inline-flex; align-items: center; gap: var(--kt-ai-space-2); color: var(--kt-ai-fg-muted); font-size: var(--kt-ai-text-xs); }
/* Срок, дней — замедленные строки */
.sl-amber { color: var(--kt-ai-status-warn-fg); font-weight: var(--kt-ai-weight-semibold); }
/* Поля карточки заявки в согласовании */
.appr-grid { display: grid; grid-template-columns: minmax(0, 1.2fr) minmax(280px, 1fr); gap: var(--kt-ai-space-6); align-items: start; }
@media (max-width: 1100px) { .appr-grid { grid-template-columns: 1fr; } }