/* ============================================================
Обзор команды — #/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 };
})();