/* ============================================================ Обзор команды — #/admin/staff Доступен: менеджер. ============================================================ */ const StaffRoster = (function () { function escHtml(s) { return String(s == null ? "" : s) .replace(/&/g, "&").replace(//g, ">").replace(/"/g, """); } async function _api(path, body = {}) { const res = await fetch(`${BACKEND_URL}/api/${path}`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ initData: tg?.initData || "", initDataUnsafe: tg?.initDataUnsafe || null, ...body }), }); if (!res.ok) throw new Error(`HTTP ${res.status}`); return res.json(); } const ROLE_LABELS = { assembler: "Сборщик", measurer: "Замерщик", expeditor: "Экспедитор", }; function mount(container) { container.innerHTML = ""; document.body.classList.remove("has-bottom-nav"); const oldNav = document.getElementById("bottom-nav"); if (oldNav) oldNav.remove(); 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.style.padding = "0 0 32px"; screen.innerHTML = `
`; container.appendChild(screen); _api("staff_roster").then(data => { if (data.error) { screen.innerHTML = `
${escHtml(data.error)}
`; return; } const staff = data.staff || []; if (!staff.length) { screen.innerHTML = `
Сотрудников пока нет
`; return; } screen.innerHTML = ""; // Разбиваем по ролям для отображения const groups = [ { key: "assembler", label: "🔨 Сборщики", items: staff.filter(s => s.roles.includes("assembler")) }, { key: "measurer", label: "📐 Замерщики", items: staff.filter(s => s.roles.includes("measurer") && !s.roles.includes("assembler")) }, { key: "expeditor", label: "📦 Экспедиторы", items: staff.filter(s => s.roles.includes("expeditor") && !s.roles.includes("assembler") && !s.roles.includes("measurer")) }, ].filter(g => g.items.length); for (const group of groups) { const headEl = document.createElement("div"); headEl.className = "section-head"; headEl.style.marginTop = "16px"; headEl.innerHTML = `${group.label} · ${group.items.length}`; screen.appendChild(headEl); for (const person of group.items) { const card = document.createElement("div"); card.style.cssText = "margin:0 16px 8px;padding:12px;background:var(--surface);border:1px solid var(--border);border-radius:12px;"; // Статус-теги const tags = []; if (person.on_probation) tags.push(`Испытательный срок`); if (person.equipment_ok === false) tags.push(`⚠️ Не укомплектован`); if (person.equipment_ok === true) tags.push(`✅ Оборудование OK`); // Нагрузка const loadBits = []; if (person.active_assemblies > 0) loadBits.push(`🔨 ${person.active_assemblies} сборок`); if (person.month_measures > 0) loadBits.push(`📐 ${person.month_measures} замеров (мес.)`); const rolesStr = person.roles .filter(r => r !== "manager" && r !== "client") .map(r => ROLE_LABELS[r] || r) .join(", "); const starsEl = (person.avg_stars != null && typeof FeedbackModule !== "undefined") ? `
${FeedbackModule.starsHtml(person.avg_stars, 13)} ${Number(person.avg_stars).toFixed(1)}
` : ""; card.innerHTML = `
${escHtml(person.full_name)}
${escHtml(rolesStr)}${person.tg_username ? ` · @${escHtml(person.tg_username)}` : ""}
${starsEl}
${loadBits.length ? `
${loadBits.join("
")}
` : `
Свободен
`}
${tags.length ? `
${tags.join("")}
` : ""} `; // Клик → действия (toggle испытательного срока) if (person.roles.includes("assembler")) { card.style.cursor = "pointer"; card.addEventListener("click", () => _showPersonActions(person, card)); } screen.appendChild(card); } } }).catch(e => { screen.innerHTML = `
Ошибка: ${escHtml(e.message)}
`; }); } function _showPersonActions(person, card) { haptic && haptic("impact"); // Inline toggle испытательного срока прямо на карточке const existing = card.querySelector(".roster-actions"); if (existing) { existing.remove(); return; } const actEl = document.createElement("div"); actEl.className = "roster-actions"; actEl.style.cssText = "margin-top:10px;padding-top:10px;border-top:1px solid var(--border);display:flex;gap:8px;flex-wrap:wrap;"; const probBtn = document.createElement("button"); probBtn.className = person.on_probation ? "btn-primary" : "btn-secondary"; probBtn.style.cssText = "font-size:12px;padding:7px 12px;"; probBtn.textContent = person.on_probation ? "✅ Снять испытательный" : "📋 Назначить испытательный"; probBtn.addEventListener("click", async (e) => { e.stopPropagation(); probBtn.disabled = true; try { const res = await _api("assembler_set_probation", { assembler_tg_id: person.tg_id, on_probation: !person.on_probation, }); if (res.ok) { person.on_probation = !person.on_probation; actEl.remove(); // Перезапускаем экран mount(document.getElementById("app")); } } catch (e) { probBtn.disabled = false; } }); actEl.appendChild(probBtn); if (person.tg_username) { const msgBtn = document.createElement("a"); msgBtn.href = `https://t.me/${person.tg_username}`; msgBtn.target = "_blank"; msgBtn.className = "btn-secondary"; msgBtn.style.cssText = "font-size:12px;padding:7px 12px;text-decoration:none;display:inline-block;"; msgBtn.textContent = "✉️ Написать"; actEl.appendChild(msgBtn); } card.appendChild(actEl); } return { mount }; })();