/* ============================================================ Детальная карточка сборки — #/c/assembly/:id Доступна клиенту, менеджеру, мастеру. ============================================================ */ const AssemblyDetailScreen = (function () { function escHtml(s) { return String(s == null ? "" : s) .replace(/&/g, "&").replace(//g, ">").replace(/"/g, """); } function fmtDate(iso) { if (!iso) return null; try { return new Date(iso).toLocaleDateString("ru-RU", { day: "numeric", month: "long", year: "numeric", hour: "2-digit", minute: "2-digit" }); } catch { return iso.slice(0, 16).replace("T", " "); } } 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: tg?.initData || "", initDataUnsafe: tg?.initDataUnsafe || null, ...body }), }); if (!res.ok) throw new Error(`Ошибка сервера (${res.status})`); return await res.json(); } catch (e) { if (e.name === "AbortError") throw new Error("Сервер не отвечает"); throw e; } finally { clearTimeout(t); } } const STATUS = { created: { icon: "🆕", text: "Создана", color: "#8e8e8e" }, scheduled: { icon: "📅", text: "Запланирована", color: "#2980B9" }, in_progress: { icon: "🔨", text: "В процессе", color: "#F39C12" }, done: { icon: "✅", text: "Завершена", color: "#27AE60" }, cancelled: { icon: "❌", text: "Отменена", color: "#C0392B" }, }; function row(label, value, opts = {}) { if (!value) return ""; return `
${escHtml(label)}
${opts.html ? value : escHtml(value)}
`; } async function mount(container, assemblyId) { container.innerHTML = ""; document.body.classList.remove("has-bottom-nav"); const oldNav = document.getElementById("bottom-nav"); if (oldNav) oldNav.remove(); // Header const h = document.createElement("header"); h.className = "podbor-header"; h.innerHTML = `
Сборка кухни
`; h.querySelector(".podbor-back").addEventListener("click", () => { haptic && haptic("impact"); history.back(); }); container.appendChild(h); const screen = document.createElement("div"); screen.className = "podbor-screen"; screen.innerHTML = `
`; container.appendChild(screen); try { const data = await _api("assembly_detail", { assembly_id: assemblyId }); if (data.error) { screen.innerHTML = `
${escHtml(data.error)}
`; return; } const sl = STATUS[data.status] || { icon: "🔧", text: data.status, color: "#8e8e8e" }; // Статус-баннер const statusBanner = `
${sl.icon}
${escHtml(sl.text)}
ID: ${escHtml(data.id)}
`; // Финансовый блок — ставки из backend (настраиваются в админке) const _kp = data.kitchen_price ? Number(data.kitchen_price) : 0; const _cr = data.client_rate_pct || 10; const _ar = data.assembler_rate_pct || 9; const _cp = data.assembly_price_for_client != null ? Number(data.assembly_price_for_client) : (_kp ? Math.round(_kp * _cr / 100) : 0); const _ap = data.assembler_payout != null ? Number(data.assembler_payout) : null; const _priceRows = _kp ? ` ${row("Стоимость кухни", _kp.toLocaleString("ru-RU") + " ₽")} ${row("Стоимость сборки (" + _cr + "%)", _cp.toLocaleString("ru-RU") + " ₽")} ${_ap != null ? row("Ваш заработок (" + _ar + "%)", Math.round(_ap).toLocaleString("ru-RU") + " ₽", {color: "var(--accent)"}) : ""} ` : ""; // Основные данные const mainBlock = `
${row("Адрес", data.address)} ${_priceRows} ${row("Объём работ", data.scope_of_work)} ${row("Дата сборки", fmtDate(data.scheduled_at))} ${row("Начало", fmtDate(data.started_at))} ${row("Завершение", fmtDate(data.completed_at))}
`; // Заметка менеджера const noteBlock = data.manager_note ? `
Заметка
${escHtml(data.manager_note)}
` : ""; // Фото результата const photosAfter = (data.photos_after || []).filter(Boolean); const photosBlock = photosAfter.length ? `
Фото результата
${photosAfter.map(u => ` фото `).join("")}
` : ""; // Подпись const VIA_LABELS = { canvas: "✍️ Подпись пальцем", code: "📱 Код подтверждения", proxy: "👤 Представитель", absent: "🚫 Без подписи", }; const signBlock = data.signed_by_name ? `
${escHtml(VIA_LABELS[data.signed_via] || "Принято")}
${escHtml(data.signed_by_name)}
${escHtml(fmtDate(data.signed_at) || "")}
${data.signed_by_phone ? `
${escHtml(data.signed_by_phone)}
` : ""}
` : `
`; // Кнопка Google Calendar const calBtn = data.gcal_event_url ? `
📅 Посмотреть в Google Календаре
` : ""; screen.innerHTML = statusBanner + mainBlock + noteBlock + photosBlock + signBlock + calBtn + `
`; // Кнопка «Подписать акт» — только если ещё не подписано if (!data.signed_by_name) { const btnWrap = screen.querySelector("#sr-sign-btn-wrap"); if (btnWrap) { const signBtn = document.createElement("button"); signBtn.className = "btn-primary"; signBtn.style.cssText = "width:100%;font-size:15px;padding:13px;"; signBtn.textContent = "✍️ Подписать акт приёмки"; signBtn.addEventListener("click", () => { haptic && haptic("impact"); if (typeof SignRequest !== "undefined") { SignRequest.open(data.id, { clientName: data.client_name || "", clientTgId: data.client_tg_id || "", onSuccess: () => { // Перерисовываем экран после подписания mount(container, assemblyId); }, }); } }); btnWrap.appendChild(signBtn); } } } catch (e) { screen.innerHTML = `
Ошибка: ${escHtml(e.message)}
`; } } return { mount }; })();