// 钓鱼事件后台管理页事件代理,替代 Blade 内联编辑和启停函数。 let adminFishingEventsControlsBound = false; let fishingEventsCache = null; /** * 读取后台 layout 注入的 CSRF token。 * * @returns {string} */ function getCsrfToken() { return document.querySelector('meta[name="csrf-token"]')?.getAttribute("content") || ""; } /** * 读取 Blade 注入的钓鱼事件快照。 * * @returns {Record>} */ function getFishingEvents() { if (fishingEventsCache !== null) { return fishingEventsCache; } const dataNode = document.getElementById("admin-fishing-events-data"); if (!dataNode?.textContent) { fishingEventsCache = {}; return fishingEventsCache; } try { fishingEventsCache = JSON.parse(dataNode.textContent); } catch (error) { // JSON 被异常截断时保持页面可用,只是不再打开编辑弹窗。 fishingEventsCache = {}; } return fishingEventsCache; } /** * 设置表单字段值。 * * @param {string} id 字段 ID * @param {unknown} value 字段值 * @returns {void} */ function setInputValue(id, value) { const input = document.getElementById(id); if (input instanceof HTMLInputElement) { input.value = String(value ?? ""); } } /** * 打开钓鱼事件编辑弹窗并填充表单。 * * @param {string} eventId 事件 ID * @returns {void} */ function openFishingEditModal(eventId) { const eventData = getFishingEvents()[eventId]; const form = document.getElementById("edit-form"); const modal = document.getElementById("edit-modal"); if (!eventData || !(form instanceof HTMLFormElement) || !modal) { return; } form.action = String(eventData.update_url || ""); setInputValue("edit-emoji", eventData.emoji); setInputValue("edit-name", eventData.name); setInputValue("edit-message", eventData.message); setInputValue("edit-exp", eventData.exp); setInputValue("edit-jjb", eventData.jjb); setInputValue("edit-weight", eventData.weight); setInputValue("edit-sort", eventData.sort); const activeInput = document.getElementById("edit-is-active"); if (activeInput instanceof HTMLInputElement) { activeInput.checked = Boolean(eventData.is_active); } modal.classList.remove("hidden"); } /** * 关闭钓鱼事件编辑弹窗。 * * @returns {void} */ function closeFishingEditModal() { document.getElementById("edit-modal")?.classList.add("hidden"); } /** * 根据接口返回状态更新钓鱼事件行和缓存。 * * @param {string} eventId 事件 ID * @param {boolean} active 是否启用 * @returns {void} */ function updateFishingToggleState(eventId, active) { const button = document.querySelector(`[data-fishing-toggle-id="${CSS.escape(eventId)}"]`); const row = document.getElementById(`row-${eventId}`); if (button instanceof HTMLButtonElement) { button.textContent = active ? "启用" : "禁用"; button.className = `px-2 py-1 rounded-full text-xs font-bold transition ${ active ? "bg-emerald-100 text-emerald-700 hover:bg-emerald-200" : "bg-gray-100 text-gray-500 hover:bg-gray-200" }`; } row?.classList.toggle("opacity-50", !active); // 缓存状态要同步,否则后续打开编辑弹窗时会显示旧的启用状态。 const eventData = getFishingEvents()[eventId]; if (eventData) { eventData.is_active = active; } } /** * 切换钓鱼事件启用状态。 * * @param {HTMLButtonElement} button 状态切换按钮 * @returns {Promise} */ async function toggleFishingEvent(button) { const eventId = button.getAttribute("data-fishing-toggle-id") || ""; const eventData = getFishingEvents()[eventId]; const toggleUrl = String(eventData?.toggle_url || ""); if (!eventId || !toggleUrl || button.disabled) { return; } button.disabled = true; try { const response = await fetch(toggleUrl, { method: "POST", headers: { "X-CSRF-TOKEN": getCsrfToken(), "Accept": "application/json", }, }); const data = await response.json(); if (data?.ok) { updateFishingToggleState(eventId, Boolean(data.is_active)); } } finally { button.disabled = false; } } /** * 绑定钓鱼事件管理页操作按钮。 * * @returns {void} */ export function bindAdminFishingEventsControls() { if (adminFishingEventsControlsBound || typeof document === "undefined") { return; } adminFishingEventsControlsBound = true; document.addEventListener("click", (event) => { if (!(event.target instanceof Element)) { return; } const editButton = event.target.closest("[data-fishing-edit-id]"); if (editButton) { event.preventDefault(); openFishingEditModal(editButton.getAttribute("data-fishing-edit-id") || ""); return; } const closeButton = event.target.closest("[data-fishing-edit-close]"); if (closeButton) { event.preventDefault(); closeFishingEditModal(); return; } const toggleButton = event.target.closest("[data-fishing-toggle-id]"); if (toggleButton instanceof HTMLButtonElement) { event.preventDefault(); void toggleFishingEvent(toggleButton); } }); }