const page = CarPassPage; const APPROVED_STATUSES = new Set(["approved", "verified"]); const MANAGER_ROLES = new Set(["owner", "manager"]); const state = { centers: [], activeCenterId: null, catalog: null, }; function activeCenter() { return state.centers.find((item) => item.id === state.activeCenterId) || null; } function roleLabel(role) { return { owner: "Владелец", manager: "Менеджер", receptionist: "Администратор", mechanic: "Механик" }[role] || role || "СТО"; } function timeValue(value) { return String(value || "").slice(0, 5); } function setScheduleForm(settings) { const form = document.querySelector("#bookingSettingsForm"); form.open_time.value = timeValue(settings.open_time || "09:00"); form.close_time.value = timeValue(settings.close_time || "18:00"); form.lunch_break_start.value = timeValue(settings.lunch_break_start || ""); form.lunch_break_end.value = timeValue(settings.lunch_break_end || ""); form.slot_duration_minutes.value = settings.slot_duration_minutes ?? 30; form.booking_buffer_minutes.value = settings.booking_buffer_minutes ?? 0; form.max_parallel_bookings.value = settings.max_parallel_bookings ?? 1; form.timezone.value = settings.timezone || "Asia/Seoul"; form.accepts_online_booking.checked = settings.accepts_online_booking !== false; const days = new Set(settings.working_days || [0, 1, 2, 3, 4]); form.querySelectorAll('[name="working_days"]').forEach((input) => { input.checked = days.has(Number(input.value)); }); } function schedulePayload(form, centerId) { const data = page.formData(form); const workingDays = [...form.querySelectorAll('[name="working_days"]:checked')].map((input) => Number(input.value)); return { service_center_id: centerId, working_days: workingDays, open_time: data.open_time || "09:00", close_time: data.close_time || "18:00", lunch_break_start: data.lunch_break_start || null, lunch_break_end: data.lunch_break_end || null, timezone: data.timezone || "Asia/Seoul", slot_duration_minutes: Number(data.slot_duration_minutes || 30), booking_buffer_minutes: Number(data.booking_buffer_minutes || 0), max_parallel_bookings: Number(data.max_parallel_bookings || 1), accepts_online_booking: Boolean(data.accepts_online_booking), }; } function catalogPayload(form, centerId) { const data = page.formData(form); const isWork = data.item_type === "work"; return { service_center_id: centerId, item_type: data.item_type, title: data.title, category: data.category || null, description: data.description || null, work_type: isWork ? (data.category || "other") : null, product_type: isWork ? null : (data.category || "other"), brand: data.brand || null, sku: data.sku || null, unit: data.unit || (isWork ? "pcs" : "pcs"), default_quantity: page.numberOrNull(data.default_quantity) || 1, default_unit_price: page.numberOrNull(data.default_unit_price) || 0, viscosity: data.viscosity || null, specification: data.specification || null, }; } function renderHeader() { const center = activeCenter(); document.querySelector("#centerSelect").innerHTML = state.centers .map((item) => ``) .join(""); if (center) document.querySelector("#centerSelect").value = String(center.id); document.querySelector("#settingsTitle").textContent = center ? (center.display_name || center.name) : "Нет доступной СТО"; document.querySelector("#settingsHint").textContent = center ? [center.city, center.address].filter(Boolean).join(", ") || "Заполните график и каталог для команды." : "Настройки доступны владельцу или менеджеру подтвержденной СТО."; document.querySelector("#roleBadge").textContent = center ? roleLabel(center.employee_role) : "Нет доступа"; } function renderCatalog() { const root = document.querySelector("#catalogList"); const centerId = activeCenter()?.id; const items = (state.catalog?.items || []).filter((item) => item.service_center_id === centerId); root.innerHTML = items.length ? items.map((item) => `
${page.escapeHtml(item.title)} ${page.escapeHtml([item.item_type === "work" ? "Работа" : "Материал", item.category, item.brand, item.sku].filter(Boolean).join(" · "))} ${page.escapeHtml(item.default_quantity)} ${page.escapeHtml(item.unit)} · ${page.escapeHtml(item.default_unit_price)}
`).join("") : `
Пока нет собственных позиций. Системный каталог уже доступен в заказ-нарядах.
`; } async function loadCenters() { const centers = await page.api("/service-centers/my"); state.centers = centers.filter((center) => APPROVED_STATUSES.has(center.verification_status) && MANAGER_ROLES.has(center.employee_role || "owner"), ); if (!state.activeCenterId && state.centers.length) state.activeCenterId = state.centers[0].id; if (state.activeCenterId && !state.centers.some((item) => item.id === state.activeCenterId)) { state.activeCenterId = state.centers[0]?.id || null; } renderHeader(); } async function loadSettings() { const center = activeCenter(); if (!center) { document.querySelector("#bookingSettingsForm").classList.add("hidden"); document.querySelector("#catalogForm").classList.add("hidden"); document.querySelector("#catalogList").innerHTML = `
Нет подтвержденной СТО с ролью владельца или менеджера.
`; return; } document.querySelector("#bookingSettingsForm").classList.remove("hidden"); document.querySelector("#catalogForm").classList.remove("hidden"); const [settings, catalog] = await Promise.all([ page.api(`/sto/settings/booking?service_center_id=${center.id}`), page.api(`/work-orders/catalog?service_center_id=${center.id}`), ]); state.catalog = catalog; setScheduleForm(settings); renderCatalog(); } document.querySelector("#centerSelect").addEventListener("change", async (event) => { state.activeCenterId = Number(event.currentTarget.value); renderHeader(); await loadSettings(); }); document.querySelector("#bookingSettingsForm").addEventListener("submit", async (event) => { event.preventDefault(); const center = activeCenter(); if (!center) return; await page.runAction(document.querySelector("#saveScheduleBtn"), "Сохраняю график...", async () => { const settings = await page.api("/sto/settings/booking", { method: "POST", body: JSON.stringify(schedulePayload(event.currentTarget, center.id)), }); setScheduleForm(settings); page.toast("График сохранен"); }); }); document.querySelector("#catalogForm").addEventListener("submit", async (event) => { event.preventDefault(); const center = activeCenter(); if (!center) return; await page.runAction(document.querySelector("#saveCatalogBtn"), "Добавляю позицию...", async () => { await page.api("/work-orders/catalog", { method: "POST", body: JSON.stringify(catalogPayload(event.currentTarget, center.id)), }); event.currentTarget.reset(); event.currentTarget.default_quantity.value = 1; event.currentTarget.default_unit_price.value = 0; state.catalog = await page.api(`/work-orders/catalog?service_center_id=${center.id}`); renderCatalog(); page.toast("Позиция добавлена"); }); }); page.boot(async () => { await loadCenters(); await loadSettings(); });