Files
site/WESP_REL/static/js/wesp-zootech-nav.js
T
2026-07-17 12:57:18 +03:00

149 lines
5.9 KiB
JavaScript

/**
* Общий навбар операторских страниц.
* <div id="wespZootechNavMount" data-active-page="recipes"></div>
*/
(function () {
/* Один файл — одинаковый слот в светлой и тёмной теме (logo.png другой aspect ratio). */
const LOGO_LIGHT = "/static/logo2.png";
const LOGO_DARK = "/static/logo2.png";
function brandLogoHtml() {
return `<img src="${LOGO_LIGHT}" alt="Комптон" class="logo logo--light-theme">
<img src="${LOGO_DARK}" alt="" class="logo logo--dark-theme" aria-hidden="true">`;
}
const PAGES = [
{ id: "recipes", href: "/recipes", icon: "fa-utensils", label: "Рецепты" },
{ id: "lab", href: "/lab", icon: "fa-flask", label: "Lab" },
{ id: "feed_dispensers", href: "/feed_dispensers", icon: "fa-server", label: "Оборудование" },
{ id: "components", href: "/components", icon: "fa-box", label: "Компоненты" },
{ id: "reports", href: "/reports", icon: "fa-chart-bar", label: "Отчеты" },
{ id: "feed_consumption", href: "/feed_consumption", icon: "fa-chart-line", label: "Учёт кормов" },
];
function navItem(page, active, mobile) {
const cls = mobile
? `mobile-menu-item${active ? " active" : ""}`
: `menu-btn${active ? " active" : ""}`;
const tag = mobile ? "a" : "a";
if (page.id === "settings") {
return `<${tag} href="javascript:void(0)" data-action="open-settings" onclick="typeof openSettings==='function'&&openSettings(event)" class="${cls}">
<i class="fas fa-cog"></i><span>Настройки</span></${tag}>`;
}
return `<${tag} href="${page.href}" class="${cls}">
<i class="fas ${page.icon}"></i><span>${page.label}</span></${tag}>`;
}
function pagesForNav(canLab) {
if (canLab) return PAGES;
return PAGES.filter((p) => p.id !== "lab");
}
function renderNav(activeId, pages) {
const desktop = pages.map((p) => navItem(p, p.id === activeId, false)).join("");
const mobile = pages.map((p) => navItem(p, p.id === activeId, true)).join("");
const settingsDesktop = navItem({ id: "settings" }, false, false);
const settingsMobile = navItem({ id: "settings" }, false, true);
return `<nav class="mobile-navbar">
<div class="container">
<div class="nav-content">
<div class="nav-brand">
<a href="/recipes" class="nav-logo-link" aria-label="Рецепты">
${brandLogoHtml()}
</a>
</div>
<div class="hamburger-menu" id="hamburgerMenu" role="button" aria-label="Меню" tabindex="0">
<div class="hamburger-line"></div>
<div class="hamburger-line"></div>
<div class="hamburger-line"></div>
</div>
<div class="desktop-menu">${desktop}${settingsDesktop}</div>
<div class="user-section">
<span id="userInfo" class="user-info"><i class="fas fa-user"></i> <span id="userLogin"></span></span>
<a href="#" data-action="logout" onclick="typeof logout==='function'&&logout();return false;" class="logout-btn">
<i class="fas fa-sign-out-alt"></i><span>Выход</span>
</a>
</div>
</div>
</div>
<div class="mobile-menu-overlay" id="mobileMenuOverlay">
<div class="mobile-menu">
<div class="mobile-menu-header">
<div class="mobile-brand">
<a href="/recipes" class="nav-logo-link" aria-label="Рецепты">
${brandLogoHtml()}
</a>
</div>
<div class="close-menu" id="closeMenu" role="button" aria-label="Закрыть" tabindex="0">
<i class="fas fa-times"></i>
</div>
</div>
<div class="mobile-menu-items">${mobile}${settingsMobile}</div>
<div class="mobile-menu-footer">
<div class="mobile-user-info" id="mobileUserInfo"></div>
<a href="#" data-action="logout" onclick="typeof logout==='function'&&logout();return false;" class="mobile-logout-btn">
<i class="fas fa-sign-out-alt"></i><span>Выход</span>
</a>
</div>
</div>
</div>
</nav>`;
}
function wireMobileMenu() {
const hamburgerMenu = document.getElementById("hamburgerMenu");
const mobileMenuOverlay = document.getElementById("mobileMenuOverlay");
const closeMenu = document.getElementById("closeMenu");
if (!hamburgerMenu || !mobileMenuOverlay) return;
const open = () => {
mobileMenuOverlay.classList.add("active");
hamburgerMenu.classList.add("active");
};
const close = () => {
mobileMenuOverlay.classList.remove("active");
hamburgerMenu.classList.remove("active");
};
hamburgerMenu.addEventListener("click", open);
closeMenu?.addEventListener("click", close);
mobileMenuOverlay.addEventListener("click", (e) => {
if (e.target === mobileMenuOverlay) close();
});
}
async function fetchCanLab() {
try {
const response = await fetch("/api/auth/check");
const data = await response.json();
if (data.status === "success" && data.authenticated) {
return Boolean(data.can_lab);
}
} catch (error) {
console.error("Ошибка проверки доступа к Lab:", error);
}
return false;
}
async function mount() {
const mountEl = document.getElementById("wespZootechNavMount");
if (!mountEl) return;
const active = mountEl.getAttribute("data-active-page") || "";
const canLab = await fetchCanLab();
window.WESP_CAN_LAB = canLab;
mountEl.outerHTML = renderNav(active, pagesForNav(canLab));
wireMobileMenu();
window.WespPageEnter?.init?.();
window.WespLabAccess?.apply?.(canLab);
}
window.WespZootechNav = { remount: mount };
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", mount);
} else {
mount();
}
})();