/* ============================================================ Акт №4 — приёмка товара (экспедитор / сборщик) #/assembly/:id/act4 ============================================================ */ const Act4Screen = (function () { "use strict"; function escHtml(s) { return String(s == null ? "" : s) .replace(/&/g, "&").replace(//g, ">").replace(/"/g, """); } function el(html) { const t = document.createElement("template"); t.innerHTML = html.trim(); return t.content.firstChild; } async function _api(path, body = {}) { const ctrl = new AbortController(); const t = setTimeout(() => ctrl.abort(), 15000); try { const res = await fetch(`${BACKEND_URL}/api/${path}`, { method: "POST", signal: ctrl.signal, headers: { "Content-Type": "application/json" }, body: JSON.stringify({ initData: typeof Platform !== "undefined" ? Platform.initData : (window.tg?.initData || ""), initDataUnsafe: typeof Platform !== "undefined" ? Platform.initDataUnsafe : null, ...body, }), }); if (!res.ok) throw new Error(`HTTP ${res.status}`); return await res.json(); } catch (e) { if (e.name === "AbortError") throw new Error("Сервер не отвечает"); throw e; } finally { clearTimeout(t); } } // Состояние акта let _state = { act_num: "", act_date: "", supplier: "", notes: "", items: [], // [{id, name, qty, condition, note}] signed_by_name: "", signed_by_phone: "", signed_via: "", }; let _data = {}; // данные с сервера let _container = null; let _assemblyId = ""; function _itemId() { return "i" + Math.random().toString(36).slice(2, 8); } /* ── Главный mount ──────────────────────────────────────────── */ async function mount(container, assemblyId) { _container = container; _assemblyId = assemblyId; container.innerHTML = ""; document.body.classList.remove("has-bottom-nav"); document.getElementById("bottom-nav")?.remove(); const h = el(`
Акт №4 · Приёмка товара
`); h.querySelector(".podbor-back").addEventListener("click", () => { haptic && haptic("impact"); history.back(); }); container.appendChild(h); const screen = el(`
`); screen.innerHTML = `
`; container.appendChild(screen); try { const d = await _api("act4_preview", { assembly_id: assemblyId }); if (d.error) { screen.innerHTML = `
${escHtml(d.error)}
`; return; } _data = d; _state = { act_num: d.act_num || `${assemblyId}-4`, act_date: d.act_date || new Date().toISOString().slice(0, 10), supplier: d.supplier || "", notes: d.notes || "", items: (d.items || []).map(it => ({ ...it, id: it.id || _itemId() })), signed_by_name: d.signed_by_name || "", signed_by_phone: d.signed_by_phone || "", signed_via: d.signed_via || "", }; _render(screen, d.is_signed); } catch (e) { screen.innerHTML = `
Ошибка: ${escHtml(e.message)}
`; } } /* ── Рендер ─────────────────────────────────────────────────── */ function _render(screen, isSigned) { screen.innerHTML = ""; // Баннер если подписан if (isSigned) { screen.appendChild(el(`
✅ Акт подписан
${escHtml(_state.signed_by_name)} ${_state.signed_at ? " · " + escHtml(new Date(_state.signed_at).toLocaleDateString("ru-RU")) : ""}
`)); } // Данные клиента screen.appendChild(el(`
Клиент
${escHtml(_data.client_name || "—")}
${_data.address ? `
${escHtml(_data.address)}
` : ""}
`)); // Реквизиты акта const reqs = el(`
Номер акта
Дата
Поставщик
`); screen.appendChild(reqs); if (!isSigned) { reqs.querySelector("#a4-num").addEventListener("input", e => { _state.act_num = e.target.value; }); reqs.querySelector("#a4-date").addEventListener("change", e => { _state.act_date = e.target.value; }); reqs.querySelector("#a4-supplier").addEventListener("input", e => { _state.supplier = e.target.value; }); } // === Список позиций === const itemsHead = el(`
Позиции
${!isSigned ? `` : ""}
`); screen.appendChild(itemsHead); const itemsList = el(`
`); screen.appendChild(itemsList); _renderItemsList(itemsList, isSigned); if (!isSigned) { itemsHead.querySelector("#a4-add-item")?.addEventListener("click", () => { haptic && haptic("impact"); _state.items.push({ id: _itemId(), name: "", qty: 1, condition: "ok", note: "" }); _renderItemsList(itemsList, false); }); } // Итог const totalEl = el(`
`); screen.appendChild(totalEl); _renderTotal(totalEl); // Примечание const noteWrap = el(`
Примечания
`); screen.appendChild(noteWrap); if (!isSigned) { noteWrap.querySelector("#a4-notes").addEventListener("input", e => { _state.notes = e.target.value; }); } // Блок подписи if (!isSigned) { const signWrap = el(`
Подпись принявшего
`); screen.appendChild(signWrap); signWrap.querySelector("#a4-sign-name").addEventListener("input", e => { _state.signed_by_name = e.target.value; }); signWrap.querySelector("#a4-sign-phone").addEventListener("input", e => { _state.signed_by_phone = e.target.value; }); // Кнопки const btns = el(`
`); screen.appendChild(btns); const statusEl = el(`
`); screen.appendChild(statusEl); btns.querySelector("#a4-save-btn").addEventListener("click", () => _doSave(false, statusEl)); btns.querySelector("#a4-sign-btn").addEventListener("click", () => _doSave(true, statusEl)); } } /* ── Список позиций ─────────────────────────────────────────── */ function _renderItemsList(container, isSigned) { container.innerHTML = ""; if (!_state.items.length) { container.appendChild(el(`
${isSigned ? "Позиции не добавлены" : "Нажмите «+ Добавить» чтобы внести позиции"}
`)); return; } _state.items.forEach((item, idx) => { const row = el(`
${!isSigned ? `` : ""}
Кол-во
Состояние
${item.condition === "damaged" && !isSigned ? `
` : (item.note && isSigned ? `
${escHtml(item.note)}
` : "")}
`); if (!isSigned) { row.querySelector(".it-name").addEventListener("input", e => { _state.items[idx].name = e.target.value; }); row.querySelector(".it-qty").addEventListener("input", e => { _state.items[idx].qty = parseInt(e.target.value) || 1; _renderTotal(document.getElementById("a4-total")); }); row.querySelector(".it-del").addEventListener("click", () => { haptic && haptic("impact"); _state.items.splice(idx, 1); _renderItemsList(container, false); _renderTotal(document.getElementById("a4-total")); }); row.querySelectorAll(".cond-btn").forEach(btn => { btn.addEventListener("click", () => { haptic && haptic("selection"); _state.items[idx].condition = btn.dataset.cond; _renderItemsList(container, false); _renderTotal(document.getElementById("a4-total")); }); }); row.querySelector(".it-note")?.addEventListener("input", e => { _state.items[idx].note = e.target.value; }); } container.appendChild(row); }); } function _renderTotal(container) { if (!container) return; const total = _state.items.reduce((s, it) => s + (parseInt(it.qty) || 1), 0); const damaged = _state.items.filter(it => it.condition === "damaged") .reduce((s, it) => s + (parseInt(it.qty) || 1), 0); container.innerHTML = damaged > 0 ? `
Итого: ${total} позиций · ⚠️ Повреждений: ${damaged}
` : `
Итого: ${total} позиций · ✅ Без повреждений
`; } /* ── Сохранение / подпись ───────────────────────────────────── */ async function _doSave(withSign, statusEl) { haptic && haptic("impact"); if (withSign && !_state.signed_by_name.trim()) { if (statusEl) { statusEl.style.color = "#E74C3C"; statusEl.textContent = "Укажите ФИО принявшего"; } return; } if (statusEl) { statusEl.style.color = "var(--muted)"; statusEl.textContent = "Сохраняем…"; } const payload = { assembly_id: _assemblyId, act_num: _state.act_num, act_date: _state.act_date, supplier: _state.supplier, items: _state.items, notes: _state.notes, }; if (withSign) { payload.signed_by_name = _state.signed_by_name; payload.signed_by_phone = _state.signed_by_phone; payload.signed_via = "manual"; } try { const res = await _api("act4_save", payload); if (res.error) { if (statusEl) { statusEl.style.color = "#E74C3C"; statusEl.textContent = "Ошибка: " + res.error; } return; } if (withSign) { // Перезагружаем экран — покажет баннер «Подписан» mount(_container, _assemblyId); } else { if (statusEl) { statusEl.style.color = "#27AE60"; statusEl.textContent = "✅ Сохранено"; } setTimeout(() => { if (statusEl) statusEl.textContent = ""; }, 3000); } } catch (e) { if (statusEl) { statusEl.style.color = "#E74C3C"; statusEl.textContent = "Ошибка: " + e.message; } } } return { mount }; })();