ghbdtn/script.js

185 lines
7.8 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

var items = [];
var filterText = "";
async function load() {
items = await fetch("/api/items").then(function(r) { return r.json(); });
render();
}
function isComplete(r) {
return r.city && r.summa && r.date && r.fileSection && r.fio && r.docSection && r.payment &&
r.fileAttachment && r.docAttachment;
}
function paymentBadge(val) {
if (val === "оплачено") return '<span class="badge badge-paid">💰 ' + val + '</span>';
if (val === "в ожидании") return '<span class="badge badge-pending">⏳ ' + val + '</span>';
return '<span class="badge badge-unpaid">❌ ' + (val || "") + '</span>';
}
function render() {
var q = filterText.toLowerCase();
var filtered = items.filter(function(i) {
return !q ||
(i.city || "").toLowerCase().indexOf(q) !== -1 ||
(i.fio || "").toLowerCase().indexOf(q) !== -1 ||
(i.fileSection || "").toLowerCase().indexOf(q) !== -1 ||
(i.docSection || "").toLowerCase().indexOf(q) !== -1 ||
(i.payment || "").toLowerCase().indexOf(q) !== -1;
});
var tbody = document.getElementById("tbody");
var empty = document.getElementById("empty");
if (filtered.length === 0) {
tbody.innerHTML = "";
empty.style.display = "block";
} else {
empty.style.display = "none";
tbody.innerHTML = filtered.map(function(r) {
var fileLink = r.fileAttachment ? '<a href="' + esc(r.fileAttachment.path) + '" target="_blank" class="file-link">📎 ' + esc(r.fileAttachment.name) + '</a>' : '';
var docLink = r.docAttachment ? '<a href="' + esc(r.docAttachment.path) + '" target="_blank" class="file-link">📎 ' + esc(r.docAttachment.name) + '</a>' : '';
var payLink = r.paymentAttachment ? '<br><a href="' + esc(r.paymentAttachment.path) + '" target="_blank" class="file-link">📎 ' + esc(r.paymentAttachment.name) + '</a>' : '';
var rowClass = isComplete(r) ? ' class="row-complete"' : '';
return "<tr" + rowClass + ">" +
"<td>" + esc(r.city) + "</td>" +
"<td>" + (r.summa ? Number(r.summa).toLocaleString("ru-RU") : "") + " ₸</td>" +
"<td>" + esc(r.date) + "</td>" +
"<td><div>" + esc(r.fileSection) + "</div>" + fileLink + "</td>" +
"<td>" + esc(r.fio) + "</td>" +
"<td><div>" + esc(r.docSection) + "</div>" + docLink + "</td>" +
"<td>" + paymentBadge(r.payment) + payLink + "</td>" +
'<td class="actions">' +
'<button class="btn-sm btn-edit" onclick="editItem(' + r.id + ')">✏️</button>' +
'<button class="btn-sm btn-del" onclick="deleteItem(' + r.id + ')">🗑️</button>' +
"</td>" +
"</tr>";
}).join("");
}
updateStats(filtered);
}
function updateStats(filtered) {
var total = items.length;
var shown = filtered.length;
var sum = filtered.reduce(function(s, r) { return s + (parseFloat(r.summa) || 0); }, 0);
document.getElementById("stats").innerHTML =
'<span>Всего: <b>' + total + '</b></span>' +
'<span>Показано: <b>' + shown + '</b></span>' +
'<span>Сумма: <b>' + sum.toLocaleString("ru-RU") + ' ₸</b></span>';
}
function esc(s) { return (s || "").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;"); }
function openForm() {
document.getElementById("modal").style.display = "flex";
document.getElementById("formTitle").textContent = "Новая запись";
document.getElementById("form").reset();
document.getElementById("editId").value = "";
document.getElementById("previewFile").innerHTML = "";
document.getElementById("previewDoc").innerHTML = "";
document.getElementById("previewPayment").innerHTML = "";
}
function closeForm() { document.getElementById("modal").style.display = "none"; }
async function uploadFile(inputName) {
var input = document.querySelector("[name='" + inputName + "']");
if (!input || !input.files || !input.files[0]) return null;
var formData = new FormData();
formData.append("file", input.files[0]);
var resp = await fetch("/api/upload", { method: "POST", body: formData });
var result = await resp.json();
if (result.ok && result.files && result.files[0]) return result.files[0];
return null;
}
async function saveItem(e) {
e.preventDefault();
var form = e.target;
var fileData = await uploadFile("fileAttachment");
var docData = await uploadFile("docAttachment");
var payData = await uploadFile("paymentAttachment");
var data = {
city: form.city.value,
summa: form.summa.value,
date: form.date.value,
fileSection: form.fileSection.value,
fio: form.fio.value,
docSection: form.docSection.value,
payment: form.payment.value
};
var editId = document.getElementById("editId").value;
if (editId) {
var existing = items.find(function(i) { return i.id === parseInt(editId); });
data.fileAttachment = fileData || (existing ? existing.fileAttachment : null);
data.docAttachment = docData || (existing ? existing.docAttachment : null);
data.paymentAttachment = payData || (existing ? existing.paymentAttachment : null);
await fetch("/api/items/" + editId, { method: "PUT", headers: { "Content-Type": "application/json" }, body: JSON.stringify(data) });
} else {
data.fileAttachment = fileData;
data.docAttachment = docData;
data.paymentAttachment = payData;
await fetch("/api/items", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(data) });
}
closeForm();
load();
}
async function editItem(id) {
var item = items.find(function(i) { return i.id === id; });
if (!item) return;
document.getElementById("modal").style.display = "flex";
document.getElementById("formTitle").textContent = "Изменить запись";
document.getElementById("editId").value = id;
document.querySelector("[name=city]").value = item.city || "";
document.querySelector("[name=summa]").value = item.summa || "";
document.querySelector("[name=date]").value = item.date || "";
document.querySelector("[name=fileSection]").value = item.fileSection || "";
document.querySelector("[name=fio]").value = item.fio || "";
document.querySelector("[name=docSection]").value = item.docSection || "";
document.querySelector("[name=payment]").value = item.payment || "";
document.getElementById("previewFile").innerHTML = item.fileAttachment
? '<span class="attached">📎 ' + esc(item.fileAttachment.name) + '</span>'
: '';
document.getElementById("previewDoc").innerHTML = item.docAttachment
? '<span class="attached">📎 ' + esc(item.docAttachment.name) + '</span>'
: '';
document.getElementById("previewPayment").innerHTML = item.paymentAttachment
? '<span class="attached">📎 ' + esc(item.paymentAttachment.name) + '</span>'
: '';
}
async function deleteItem(id) {
if (!confirm("Удалить запись?")) return;
await fetch("/api/items/" + id, { method: "DELETE" });
load();
}
document.getElementById("search").addEventListener("input", function(e) {
filterText = e.target.value;
render();
});
function exportCsv() {
if (items.length === 0) { alert("Нет данных для выгрузки"); return; }
var head = ["Город","Сумма","Дата","Раздел для файла","Файл","ФИО","Раздел для документов","Документ","Платёж","Файл оплаты"];
var body = items.map(function(r) {
return [r.city, r.summa, r.date, r.fileSection, r.fileAttachment ? r.fileAttachment.name : "", r.fio, r.docSection, r.docAttachment ? r.docAttachment.name : "", r.payment, r.paymentAttachment ? r.paymentAttachment.name : ""]
.map(function(v) { return '"' + String(v || "").replace(/"/g, '""') + '"'; })
.join(";");
});
var csv = "\uFEFF" + [head.join(";"), ...body].join("\n");
var a = document.createElement("a");
a.href = URL.createObjectURL(new Blob([csv], { type: "text/csv" }));
a.download = "otchet.csv";
a.click();
}
load();