208 lines
5.8 KiB
JavaScript
208 lines
5.8 KiB
JavaScript
// 钓鱼事件后台管理页事件代理,替代 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<string, Record<string, unknown>>}
|
|
*/
|
|
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<void>}
|
|
*/
|
|
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);
|
|
}
|
|
});
|
|
|
|
document.addEventListener("submit", (event) => {
|
|
if (!(event.target instanceof HTMLFormElement)) {
|
|
return;
|
|
}
|
|
|
|
const confirmMessage = event.target.getAttribute("data-fishing-delete-confirm");
|
|
if (confirmMessage && !window.confirm(confirmMessage)) {
|
|
event.preventDefault();
|
|
}
|
|
});
|
|
}
|