я косяк, поправил веб. Капитан, работайте!
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -72,11 +72,36 @@
|
||||
|
||||
function load(root, enterpriseId) {
|
||||
root.innerHTML = '<p class="text-muted small">Загрузка конфликтов…</p>';
|
||||
const orch = global.__WESP_ORCH__ || {};
|
||||
if (orch.configured === false) {
|
||||
root.innerHTML =
|
||||
'<p class="text-muted small">Orchestrator не настроен. Укажите upstream, hub_site_id и api_key в админке.</p>';
|
||||
return;
|
||||
}
|
||||
if (orch.reachable === false) {
|
||||
const host = orch.upstream ? ` (${orch.upstream})` : "";
|
||||
root.innerHTML =
|
||||
`<p class="text-warning small">Orchestrator недоступен${escapeHtml(host)}. Проверьте upstream URL и что сервис запущен.</p>`;
|
||||
return;
|
||||
}
|
||||
fetch(`${API}?enterprise_id=${encodeURIComponent(enterpriseId)}`)
|
||||
.then((r) => r.json())
|
||||
.then((items) => renderList(root, items || [], enterpriseId))
|
||||
.catch(() => {
|
||||
root.innerHTML = '<p class="text-danger small">Не удалось загрузить конфликты.</p>';
|
||||
.then((r) => {
|
||||
if (!r.ok) {
|
||||
return r.json().catch(() => ({})).then((body) => {
|
||||
throw new Error(body.message || `HTTP ${r.status}`);
|
||||
});
|
||||
}
|
||||
return r.json();
|
||||
})
|
||||
.then((items) => {
|
||||
if (items && items.error) {
|
||||
throw new Error(items.message || "Orchestrator error");
|
||||
}
|
||||
renderList(root, Array.isArray(items) ? items : [], enterpriseId);
|
||||
})
|
||||
.catch((err) => {
|
||||
const msg = err && err.message ? err.message : "Не удалось загрузить конфликты.";
|
||||
root.innerHTML = `<p class="text-danger small">${escapeHtml(msg)}</p>`;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -151,44 +151,11 @@ export function createRecipesAuthSettingsController({ notyf }) {
|
||||
}
|
||||
|
||||
function setupMobileMenu() {
|
||||
const hamburgerMenu = document.getElementById("hamburgerMenu");
|
||||
const mobileMenuOverlay = document.getElementById("mobileMenuOverlay");
|
||||
const closeMenu = document.getElementById("closeMenu");
|
||||
const mobileUserInfo = document.getElementById("mobileUserInfo");
|
||||
if (!hamburgerMenu || !mobileMenuOverlay || !closeMenu) return;
|
||||
|
||||
hamburgerMenu.addEventListener("click", () => {
|
||||
mobileMenuOverlay.classList.add("active");
|
||||
hamburgerMenu.classList.add("active");
|
||||
document.body.style.overflow = "hidden";
|
||||
const userInfo = document.getElementById("userInfo");
|
||||
if (userInfo && mobileUserInfo) {
|
||||
mobileUserInfo.textContent = userInfo.textContent || "";
|
||||
}
|
||||
});
|
||||
|
||||
const closeMobileMenu = () => {
|
||||
mobileMenuOverlay.classList.remove("active");
|
||||
hamburgerMenu.classList.remove("active");
|
||||
document.body.style.overflow = "";
|
||||
};
|
||||
|
||||
closeMenu.addEventListener("click", closeMobileMenu);
|
||||
mobileMenuOverlay.addEventListener("click", (e) => {
|
||||
if (e.target === mobileMenuOverlay) closeMobileMenu();
|
||||
});
|
||||
document.addEventListener("keydown", (e) => {
|
||||
if (e.key === "Escape" && mobileMenuOverlay.classList.contains("active")) {
|
||||
closeMobileMenu();
|
||||
}
|
||||
});
|
||||
|
||||
const mobileMenuItems = document.querySelectorAll(".mobile-menu-item");
|
||||
mobileMenuItems.forEach((item) => {
|
||||
item.addEventListener("click", () => {
|
||||
setTimeout(closeMobileMenu, 300);
|
||||
});
|
||||
});
|
||||
const userInfo = document.getElementById("userInfo");
|
||||
if (userInfo && mobileUserInfo) {
|
||||
mobileUserInfo.textContent = userInfo.textContent?.trim() || "";
|
||||
}
|
||||
}
|
||||
|
||||
async function loadSyncClientsSettings() {
|
||||
|
||||
@@ -24,6 +24,8 @@
|
||||
let activePreset = "day";
|
||||
let panelEl = null;
|
||||
let triggerEl = null;
|
||||
let isOpen = false;
|
||||
let suppressOutsideCloseUntil = 0;
|
||||
|
||||
function pad(n) {
|
||||
return String(n).padStart(2, "0");
|
||||
@@ -90,7 +92,7 @@
|
||||
|
||||
function setPresetActive(preset) {
|
||||
activePreset = preset || "";
|
||||
document.querySelectorAll("[data-drp-preset]").forEach((btn) => {
|
||||
panelEl?.querySelectorAll("[data-drp-preset]").forEach((btn) => {
|
||||
btn.classList.toggle("active", btn.getAttribute("data-drp-preset") === activePreset);
|
||||
});
|
||||
}
|
||||
@@ -131,7 +133,7 @@
|
||||
}
|
||||
|
||||
function positionPanel() {
|
||||
if (!triggerEl || !panelEl || panelEl.hidden) return;
|
||||
if (!triggerEl || !panelEl || !isOpen) return;
|
||||
const rect = triggerEl.getBoundingClientRect();
|
||||
const width = Math.max(rect.width, 304);
|
||||
let left = rect.left;
|
||||
@@ -149,28 +151,51 @@
|
||||
}
|
||||
|
||||
function closePanel() {
|
||||
if (panelEl) panelEl.hidden = true;
|
||||
isOpen = false;
|
||||
suppressOutsideCloseUntil = 0;
|
||||
if (panelEl) {
|
||||
panelEl.hidden = true;
|
||||
panelEl.setAttribute("hidden", "");
|
||||
panelEl.classList.remove("reports-drp__panel--open");
|
||||
panelEl.style.left = "";
|
||||
panelEl.style.top = "";
|
||||
panelEl.style.width = "";
|
||||
}
|
||||
if (triggerEl) triggerEl.setAttribute("aria-expanded", "false");
|
||||
window.removeEventListener("resize", positionPanel);
|
||||
window.removeEventListener("scroll", positionPanel, true);
|
||||
}
|
||||
|
||||
function isPanelTarget(target) {
|
||||
if (!target || !panelEl || !triggerEl) return false;
|
||||
return triggerEl.contains(target) || panelEl.contains(target);
|
||||
}
|
||||
|
||||
function openPanel() {
|
||||
const committed = readCommittedRange();
|
||||
draftFrom = committed.from || today();
|
||||
draftTo = committed.to || draftFrom;
|
||||
viewMonth = new Date(draftFrom.getFullYear(), draftFrom.getMonth(), 1);
|
||||
renderCalendar();
|
||||
if (panelEl) panelEl.hidden = false;
|
||||
global.WespReportsFilterDropdown?.closeAll?.();
|
||||
global.WespReportsExport?.close?.();
|
||||
isOpen = true;
|
||||
suppressOutsideCloseUntil = Date.now() + 180;
|
||||
if (panelEl) {
|
||||
panelEl.removeAttribute("hidden");
|
||||
panelEl.hidden = false;
|
||||
panelEl.classList.add("reports-drp__panel--open");
|
||||
}
|
||||
if (triggerEl) triggerEl.setAttribute("aria-expanded", "true");
|
||||
positionPanel();
|
||||
requestAnimationFrame(() => positionPanel());
|
||||
window.addEventListener("resize", positionPanel);
|
||||
window.addEventListener("scroll", positionPanel, true);
|
||||
}
|
||||
|
||||
function togglePanel() {
|
||||
if (panelEl?.hidden) openPanel();
|
||||
else closePanel();
|
||||
if (isOpen) closePanel();
|
||||
else openPanel();
|
||||
}
|
||||
|
||||
function inRange(d, a, b) {
|
||||
@@ -246,6 +271,8 @@
|
||||
triggerEl = document.getElementById("reportsDateRangeTrigger");
|
||||
panelEl = document.getElementById("reportsDateRangePanel");
|
||||
if (!triggerEl || !panelEl) return;
|
||||
if (triggerEl.dataset.drpWired === "1") return;
|
||||
triggerEl.dataset.drpWired = "1";
|
||||
|
||||
if (panelEl.parentElement !== document.body) {
|
||||
document.body.appendChild(panelEl);
|
||||
@@ -254,7 +281,7 @@
|
||||
panelEl.addEventListener("mousedown", (e) => e.stopPropagation());
|
||||
panelEl.addEventListener("click", (e) => e.stopPropagation());
|
||||
|
||||
document.querySelectorAll("[data-drp-preset]").forEach((btn) => {
|
||||
panelEl.querySelectorAll("[data-drp-preset]").forEach((btn) => {
|
||||
btn.addEventListener("click", (e) => {
|
||||
e.stopPropagation();
|
||||
setPeriod(btn.getAttribute("data-drp-preset") || "day");
|
||||
@@ -276,22 +303,36 @@
|
||||
positionPanel();
|
||||
});
|
||||
|
||||
triggerEl.addEventListener("click", (e) => {
|
||||
e.stopPropagation();
|
||||
togglePanel();
|
||||
});
|
||||
triggerEl.addEventListener(
|
||||
"pointerdown",
|
||||
(e) => {
|
||||
if (e.button !== 0) return;
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
e.stopImmediatePropagation();
|
||||
togglePanel();
|
||||
},
|
||||
true
|
||||
);
|
||||
|
||||
document.addEventListener("click", () => {
|
||||
if (!panelEl.hidden) closePanel();
|
||||
});
|
||||
document.addEventListener(
|
||||
"pointerdown",
|
||||
(e) => {
|
||||
if (Date.now() < suppressOutsideCloseUntil) return;
|
||||
if (!isOpen) return;
|
||||
if (isPanelTarget(e.target)) return;
|
||||
closePanel();
|
||||
},
|
||||
true
|
||||
);
|
||||
|
||||
document.addEventListener("keydown", (e) => {
|
||||
if (e.key === "Escape") closePanel();
|
||||
if (e.key === "Escape" && isOpen) closePanel();
|
||||
});
|
||||
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
const highlightReportId = urlParams.get("report");
|
||||
if highlightReportId) {
|
||||
if (highlightReportId) {
|
||||
global.__wespHighlightReportId = highlightReportId;
|
||||
setPeriod("month");
|
||||
} else {
|
||||
@@ -305,6 +346,7 @@
|
||||
init,
|
||||
setPeriod,
|
||||
commit: commitDraft,
|
||||
close: closePanel,
|
||||
updateTriggerLabel,
|
||||
formatLabel,
|
||||
parseIso,
|
||||
|
||||
@@ -2,6 +2,11 @@
|
||||
* Экспорт /reports — выбор раздела и формата (Excel / PDF).
|
||||
*/
|
||||
(function (global) {
|
||||
let btnEl = null;
|
||||
let menuEl = null;
|
||||
let isOpen = false;
|
||||
let suppressOutsideCloseUntil = 0;
|
||||
|
||||
function appendFilterContext(params) {
|
||||
const farms = global.WespReportsFilters?.getSelectedFarmNames?.() || [];
|
||||
const dispensers = global.WespReportsFilters?.getSelectedDispenserNames?.() || [];
|
||||
@@ -34,34 +39,89 @@
|
||||
window.location.href = buildExportUrl(format, section);
|
||||
}
|
||||
|
||||
function isMenuTarget(target) {
|
||||
if (!target || !btnEl || !menuEl) return false;
|
||||
return btnEl.contains(target) || menuEl.contains(target);
|
||||
}
|
||||
|
||||
function positionMenu() {
|
||||
if (!btnEl || !menuEl || !isOpen) return;
|
||||
const rect = btnEl.getBoundingClientRect();
|
||||
let top = rect.bottom + 6;
|
||||
const menuHeight = menuEl.offsetHeight || 320;
|
||||
if (top + menuHeight > window.innerHeight - 12) {
|
||||
top = Math.max(12, rect.top - menuHeight - 6);
|
||||
}
|
||||
menuEl.style.top = `${top}px`;
|
||||
menuEl.style.right = `${Math.max(12, window.innerWidth - rect.right)}px`;
|
||||
menuEl.style.left = "auto";
|
||||
menuEl.style.width = "";
|
||||
menuEl.style.transform = "";
|
||||
}
|
||||
|
||||
function closeMenu() {
|
||||
const menu = document.getElementById("reportsExportMenu");
|
||||
const btn = document.getElementById("reportsExportBtn");
|
||||
if (menu) menu.hidden = true;
|
||||
if (btn) btn.setAttribute("aria-expanded", "false");
|
||||
isOpen = false;
|
||||
suppressOutsideCloseUntil = 0;
|
||||
if (menuEl) {
|
||||
menuEl.hidden = true;
|
||||
menuEl.setAttribute("hidden", "");
|
||||
menuEl.classList.remove("reports-export-dropdown__menu--open");
|
||||
menuEl.style.top = "";
|
||||
menuEl.style.right = "";
|
||||
menuEl.style.left = "";
|
||||
menuEl.style.width = "";
|
||||
menuEl.style.transform = "";
|
||||
}
|
||||
if (btnEl) btnEl.setAttribute("aria-expanded", "false");
|
||||
window.removeEventListener("resize", positionMenu);
|
||||
window.removeEventListener("scroll", positionMenu, true);
|
||||
}
|
||||
|
||||
function openMenu() {
|
||||
global.WespReportsDateRange?.close?.();
|
||||
global.WespReportsFilterDropdown?.closeAll?.();
|
||||
isOpen = true;
|
||||
suppressOutsideCloseUntil = Date.now() + 180;
|
||||
if (menuEl) {
|
||||
menuEl.removeAttribute("hidden");
|
||||
menuEl.hidden = false;
|
||||
menuEl.classList.add("reports-export-dropdown__menu--open");
|
||||
}
|
||||
if (btnEl) btnEl.setAttribute("aria-expanded", "true");
|
||||
positionMenu();
|
||||
requestAnimationFrame(() => positionMenu());
|
||||
window.addEventListener("resize", positionMenu);
|
||||
window.addEventListener("scroll", positionMenu, true);
|
||||
}
|
||||
|
||||
function toggleMenu() {
|
||||
const menu = document.getElementById("reportsExportMenu");
|
||||
const btn = document.getElementById("reportsExportBtn");
|
||||
if (!menu || !btn) return;
|
||||
const open = menu.hidden;
|
||||
menu.hidden = !open;
|
||||
btn.setAttribute("aria-expanded", open ? "true" : "false");
|
||||
if (isOpen) closeMenu();
|
||||
else openMenu();
|
||||
}
|
||||
|
||||
function init() {
|
||||
const btn = document.getElementById("reportsExportBtn");
|
||||
const menu = document.getElementById("reportsExportMenu");
|
||||
if (!btn || !menu || btn.dataset.bound) return;
|
||||
btn.dataset.bound = "1";
|
||||
btnEl = document.getElementById("reportsExportBtn");
|
||||
menuEl = document.getElementById("reportsExportMenu");
|
||||
if (!btnEl || !menuEl || btnEl.dataset.bound) return;
|
||||
btnEl.dataset.bound = "1";
|
||||
|
||||
btn.addEventListener("click", (e) => {
|
||||
e.stopPropagation();
|
||||
toggleMenu();
|
||||
});
|
||||
if (menuEl.parentElement !== document.body) {
|
||||
document.body.appendChild(menuEl);
|
||||
}
|
||||
|
||||
menu.querySelectorAll("[data-reports-export-format]").forEach((item) => {
|
||||
btnEl.addEventListener(
|
||||
"pointerdown",
|
||||
(e) => {
|
||||
if (e.button !== 0) return;
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
e.stopImmediatePropagation();
|
||||
toggleMenu();
|
||||
},
|
||||
true
|
||||
);
|
||||
|
||||
menuEl.querySelectorAll("[data-reports-export-format]").forEach((item) => {
|
||||
item.addEventListener("click", (e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
@@ -73,14 +133,30 @@
|
||||
});
|
||||
});
|
||||
|
||||
menu.addEventListener("mousedown", (e) => e.stopPropagation());
|
||||
menu.addEventListener("click", (e) => e.stopPropagation());
|
||||
menuEl.addEventListener("mousedown", (e) => e.stopPropagation());
|
||||
menuEl.addEventListener("click", (e) => e.stopPropagation());
|
||||
|
||||
document.addEventListener(
|
||||
"pointerdown",
|
||||
(e) => {
|
||||
if (Date.now() < suppressOutsideCloseUntil) return;
|
||||
if (!isOpen) return;
|
||||
if (isMenuTarget(e.target)) return;
|
||||
closeMenu();
|
||||
},
|
||||
true
|
||||
);
|
||||
|
||||
document.addEventListener("click", () => closeMenu());
|
||||
document.addEventListener("keydown", (e) => {
|
||||
if (e.key === "Escape") closeMenu();
|
||||
if (e.key === "Escape" && isOpen) closeMenu();
|
||||
});
|
||||
}
|
||||
|
||||
global.WespReportsExport = { init, buildExportUrl, download, appendFilterContext };
|
||||
global.WespReportsExport = {
|
||||
init,
|
||||
buildExportUrl,
|
||||
download,
|
||||
appendFilterContext,
|
||||
close: closeMenu,
|
||||
};
|
||||
})(typeof window !== "undefined" ? window : globalThis);
|
||||
|
||||
@@ -217,6 +217,7 @@
|
||||
trigger.addEventListener("click", (e) => {
|
||||
e.stopPropagation();
|
||||
const willOpen = menu.hidden;
|
||||
global.WespReportsDateRange?.close?.();
|
||||
closeAll(willOpen ? menu : null);
|
||||
menu.hidden = !willOpen;
|
||||
trigger.setAttribute("aria-expanded", willOpen ? "true" : "false");
|
||||
@@ -250,11 +251,25 @@
|
||||
return api;
|
||||
}
|
||||
|
||||
function isReportsPopoverTarget(target) {
|
||||
if (!target) return false;
|
||||
const roots = [
|
||||
"reportsDateRangeTrigger",
|
||||
"reportsDateRangePanel",
|
||||
"reportsExportBtn",
|
||||
"reportsExportMenu",
|
||||
];
|
||||
return roots.some((id) => document.getElementById(id)?.contains(target));
|
||||
}
|
||||
|
||||
function init() {
|
||||
bindSelect("farm-select");
|
||||
bindSelect("dispenser-select");
|
||||
bindSelect("recipe-select");
|
||||
document.addEventListener("click", () => closeAll());
|
||||
document.addEventListener("click", (e) => {
|
||||
if (isReportsPopoverTarget(e.target)) return;
|
||||
closeAll();
|
||||
});
|
||||
document.addEventListener("keydown", (e) => {
|
||||
if (e.key === "Escape") closeAll();
|
||||
});
|
||||
@@ -278,5 +293,6 @@
|
||||
bindSelect,
|
||||
getMultiSelectValues,
|
||||
setMultiSelectValues,
|
||||
closeAll,
|
||||
};
|
||||
})(typeof window !== "undefined" ? window : globalThis);
|
||||
|
||||
@@ -132,6 +132,15 @@
|
||||
|
||||
function buildAlertsParams() {
|
||||
const params = new URLSearchParams(getDateParams());
|
||||
const recipeIds = getRecipeIds();
|
||||
if (recipeIds.length === 1) {
|
||||
params.set("recipe_id", recipeIds[0]);
|
||||
return params;
|
||||
}
|
||||
if (recipeIds.length > 1) {
|
||||
params.set("recipe_ids", recipeIds.join(","));
|
||||
return params;
|
||||
}
|
||||
const dispenserIds = getDispenserIds();
|
||||
if (dispenserIds.length === 1) {
|
||||
params.set("dispenser_id", dispenserIds[0]);
|
||||
|
||||
Reference in New Issue
Block a user