迁移签到规则后台脚本
This commit is contained in:
@@ -0,0 +1,177 @@
|
|||||||
|
// 签到奖励规则后台管理页事件代理,替代 Blade 内联编辑、删除确认和启停函数。
|
||||||
|
|
||||||
|
let adminSignInRulesControlsBound = false;
|
||||||
|
let signInRulesCache = null;
|
||||||
|
|
||||||
|
const SIGN_IN_RULE_FIELDS = [
|
||||||
|
"streak_days",
|
||||||
|
"gold_reward",
|
||||||
|
"exp_reward",
|
||||||
|
"charm_reward",
|
||||||
|
"identity_badge_code",
|
||||||
|
"identity_badge_name",
|
||||||
|
"identity_badge_icon",
|
||||||
|
"identity_badge_color",
|
||||||
|
"identity_duration_days",
|
||||||
|
"sort_order",
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 读取后台 layout 注入的 CSRF token。
|
||||||
|
*
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
function getCsrfToken() {
|
||||||
|
return document.querySelector('meta[name="csrf-token"]')?.getAttribute("content") || "";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 读取 Blade 注入的签到规则快照。
|
||||||
|
*
|
||||||
|
* @returns {Record<string, Record<string, unknown>>}
|
||||||
|
*/
|
||||||
|
function getSignInRules() {
|
||||||
|
if (signInRulesCache !== null) {
|
||||||
|
return signInRulesCache;
|
||||||
|
}
|
||||||
|
|
||||||
|
const dataNode = document.getElementById("admin-sign-in-rules-data");
|
||||||
|
if (!dataNode?.textContent) {
|
||||||
|
signInRulesCache = {};
|
||||||
|
return signInRulesCache;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
signInRulesCache = JSON.parse(dataNode.textContent);
|
||||||
|
} catch (error) {
|
||||||
|
// 数据块异常时不影响新增和删除表单,编辑弹窗会自然不可打开。
|
||||||
|
signInRulesCache = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
return signInRulesCache;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 打开签到规则编辑弹窗并填充表单。
|
||||||
|
*
|
||||||
|
* @param {string} ruleId 规则 ID
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
function openSignInRuleModal(ruleId) {
|
||||||
|
const rule = getSignInRules()[ruleId];
|
||||||
|
const form = document.getElementById("edit-rule-form");
|
||||||
|
const modal = document.getElementById("edit-rule-modal");
|
||||||
|
|
||||||
|
if (!rule || !(form instanceof HTMLFormElement) || !modal) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
form.action = String(rule.update_url || "");
|
||||||
|
SIGN_IN_RULE_FIELDS.forEach((field) => {
|
||||||
|
const input = document.getElementById(`edit-${field}`);
|
||||||
|
if (input instanceof HTMLInputElement) {
|
||||||
|
input.value = String(rule[field] ?? "");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const enabledInput = document.getElementById("edit-is-enabled");
|
||||||
|
if (enabledInput instanceof HTMLInputElement) {
|
||||||
|
enabledInput.checked = Boolean(rule.is_enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
modal.classList.remove("hidden");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 关闭签到规则编辑弹窗。
|
||||||
|
*
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
function closeSignInRuleModal() {
|
||||||
|
document.getElementById("edit-rule-modal")?.classList.add("hidden");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 切换签到规则启停状态,低风险沿用旧逻辑:成功后刷新页面。
|
||||||
|
*
|
||||||
|
* @param {HTMLButtonElement} button 启停按钮
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
|
async function toggleSignInRule(button) {
|
||||||
|
const toggleUrl = button.getAttribute("data-sign-in-rule-toggle-url") || "";
|
||||||
|
|
||||||
|
if (!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 (!response.ok || !data?.ok) {
|
||||||
|
window.alert(data?.message || "切换失败");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
window.location.reload();
|
||||||
|
} finally {
|
||||||
|
button.disabled = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 绑定签到奖励规则管理页操作按钮。
|
||||||
|
*
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
export function bindAdminSignInRulesControls() {
|
||||||
|
if (adminSignInRulesControlsBound || typeof document === "undefined") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
adminSignInRulesControlsBound = true;
|
||||||
|
document.addEventListener("click", (event) => {
|
||||||
|
if (!(event.target instanceof Element)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const editButton = event.target.closest("[data-sign-in-rule-edit-id]");
|
||||||
|
if (editButton) {
|
||||||
|
event.preventDefault();
|
||||||
|
openSignInRuleModal(editButton.getAttribute("data-sign-in-rule-edit-id") || "");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const closeButton = event.target.closest("[data-sign-in-rule-close]");
|
||||||
|
if (closeButton) {
|
||||||
|
event.preventDefault();
|
||||||
|
closeSignInRuleModal();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const toggleButton = event.target.closest("[data-sign-in-rule-toggle-url]");
|
||||||
|
if (toggleButton instanceof HTMLButtonElement) {
|
||||||
|
event.preventDefault();
|
||||||
|
void toggleSignInRule(toggleButton);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
document.addEventListener("submit", (event) => {
|
||||||
|
if (!(event.target instanceof HTMLFormElement)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const confirmMessage = event.target.getAttribute("data-sign-in-rule-delete-confirm");
|
||||||
|
if (confirmMessage && !window.confirm(confirmMessage)) {
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -1,7 +1,9 @@
|
|||||||
import './bootstrap';
|
import './bootstrap';
|
||||||
import { bindAdminAutoactControls } from './admin/autoact.js';
|
import { bindAdminAutoactControls } from './admin/autoact.js';
|
||||||
import { bindAdminFishingEventsControls } from './admin/fishing-events.js';
|
import { bindAdminFishingEventsControls } from './admin/fishing-events.js';
|
||||||
|
import { bindAdminSignInRulesControls } from './admin/sign-in-rules.js';
|
||||||
|
|
||||||
// 后台共用入口只注册轻量事件代理,具体页面通过 data-* 属性决定是否响应。
|
// 后台共用入口只注册轻量事件代理,具体页面通过 data-* 属性决定是否响应。
|
||||||
bindAdminAutoactControls();
|
bindAdminAutoactControls();
|
||||||
bindAdminFishingEventsControls();
|
bindAdminFishingEventsControls();
|
||||||
|
bindAdminSignInRulesControls();
|
||||||
|
|||||||
@@ -3,6 +3,30 @@
|
|||||||
@section('title', '签到奖励管理')
|
@section('title', '签到奖励管理')
|
||||||
|
|
||||||
@section('content')
|
@section('content')
|
||||||
|
@php
|
||||||
|
$signInRulePayload = $rules->mapWithKeys(
|
||||||
|
fn($rule) => [
|
||||||
|
(string) $rule->id => [
|
||||||
|
'id' => $rule->id,
|
||||||
|
'streak_days' => $rule->streak_days,
|
||||||
|
'gold_reward' => $rule->gold_reward,
|
||||||
|
'exp_reward' => $rule->exp_reward,
|
||||||
|
'charm_reward' => $rule->charm_reward,
|
||||||
|
'identity_badge_code' => $rule->identity_badge_code,
|
||||||
|
'identity_badge_name' => $rule->identity_badge_name,
|
||||||
|
'identity_badge_icon' => $rule->identity_badge_icon,
|
||||||
|
'identity_badge_color' => $rule->identity_badge_color,
|
||||||
|
'identity_duration_days' => $rule->identity_duration_days,
|
||||||
|
'sort_order' => $rule->sort_order,
|
||||||
|
'is_enabled' => (bool) $rule->is_enabled,
|
||||||
|
'update_url' => route('admin.sign-in-rules.update', $rule),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
);
|
||||||
|
@endphp
|
||||||
|
|
||||||
|
<script type="application/json" id="admin-sign-in-rules-data">@json($signInRulePayload)</script>
|
||||||
|
|
||||||
<div class="space-y-6">
|
<div class="space-y-6">
|
||||||
<div class="bg-white rounded-xl shadow-sm border border-gray-100 p-6 flex justify-between items-center">
|
<div class="bg-white rounded-xl shadow-sm border border-gray-100 p-6 flex justify-between items-center">
|
||||||
<div>
|
<div>
|
||||||
@@ -48,18 +72,19 @@
|
|||||||
{{ $rule->identity_duration_days > 0 ? $rule->identity_duration_days . ' 天' : '永久' }}
|
{{ $rule->identity_duration_days > 0 ? $rule->identity_duration_days . ' 天' : '永久' }}
|
||||||
</td>
|
</td>
|
||||||
<td class="px-4 py-3 text-center">
|
<td class="px-4 py-3 text-center">
|
||||||
<button onclick="toggleSignInRule({{ $rule->id }})" id="toggle-rule-{{ $rule->id }}"
|
<button type="button" data-sign-in-rule-toggle-url="{{ route('admin.sign-in-rules.toggle', $rule) }}"
|
||||||
|
id="toggle-rule-{{ $rule->id }}"
|
||||||
class="px-2 py-1 rounded-full text-xs font-bold transition {{ $rule->is_enabled ? 'bg-emerald-100 text-emerald-700 hover:bg-emerald-200' : 'bg-gray-100 text-gray-500 hover:bg-gray-200' }}">
|
class="px-2 py-1 rounded-full text-xs font-bold transition {{ $rule->is_enabled ? 'bg-emerald-100 text-emerald-700 hover:bg-emerald-200' : 'bg-gray-100 text-gray-500 hover:bg-gray-200' }}">
|
||||||
{{ $rule->is_enabled ? '启用' : '停用' }}
|
{{ $rule->is_enabled ? '启用' : '停用' }}
|
||||||
</button>
|
</button>
|
||||||
</td>
|
</td>
|
||||||
<td class="px-4 py-3 text-right">
|
<td class="px-4 py-3 text-right">
|
||||||
<button type="button" onclick="openEditRule({{ $rule->id }})"
|
<button type="button" data-sign-in-rule-edit-id="{{ $rule->id }}"
|
||||||
class="px-3 py-1 bg-indigo-50 text-indigo-700 rounded text-xs font-bold hover:bg-indigo-100 transition mr-1">
|
class="px-3 py-1 bg-indigo-50 text-indigo-700 rounded text-xs font-bold hover:bg-indigo-100 transition mr-1">
|
||||||
编辑
|
编辑
|
||||||
</button>
|
</button>
|
||||||
<form action="{{ route('admin.sign-in-rules.destroy', $rule) }}" method="POST"
|
<form action="{{ route('admin.sign-in-rules.destroy', $rule) }}" method="POST"
|
||||||
class="inline" onsubmit="return confirm('确定删除第 {{ $rule->streak_days }} 天签到规则?')">
|
class="inline" data-sign-in-rule-delete-confirm="确定删除第 {{ $rule->streak_days }} 天签到规则?">
|
||||||
@csrf
|
@csrf
|
||||||
@method('DELETE')
|
@method('DELETE')
|
||||||
<button type="submit"
|
<button type="submit"
|
||||||
@@ -103,7 +128,7 @@
|
|||||||
<div class="bg-white rounded-xl w-full max-w-3xl shadow-2xl">
|
<div class="bg-white rounded-xl w-full max-w-3xl shadow-2xl">
|
||||||
<div class="p-5 border-b border-gray-100 flex justify-between items-center">
|
<div class="p-5 border-b border-gray-100 flex justify-between items-center">
|
||||||
<h3 class="font-bold text-gray-800">✏️ 编辑签到规则</h3>
|
<h3 class="font-bold text-gray-800">✏️ 编辑签到规则</h3>
|
||||||
<button type="button" onclick="closeEditRule()" class="text-gray-400 hover:text-gray-600 text-xl">✕</button>
|
<button type="button" data-sign-in-rule-close class="text-gray-400 hover:text-gray-600 text-xl">✕</button>
|
||||||
</div>
|
</div>
|
||||||
<form id="edit-rule-form" method="POST" class="p-5">
|
<form id="edit-rule-form" method="POST" class="p-5">
|
||||||
@csrf
|
@csrf
|
||||||
@@ -118,7 +143,7 @@
|
|||||||
<input type="checkbox" name="is_enabled" id="edit-is-enabled" value="1" class="rounded">
|
<input type="checkbox" name="is_enabled" id="edit-is-enabled" value="1" class="rounded">
|
||||||
启用此规则
|
启用此规则
|
||||||
</label>
|
</label>
|
||||||
<button type="button" onclick="closeEditRule()"
|
<button type="button" data-sign-in-rule-close
|
||||||
class="px-4 py-2 bg-gray-100 text-gray-700 rounded-lg font-bold hover:bg-gray-200 transition text-sm">
|
class="px-4 py-2 bg-gray-100 text-gray-700 rounded-lg font-bold hover:bg-gray-200 transition text-sm">
|
||||||
取消
|
取消
|
||||||
</button>
|
</button>
|
||||||
@@ -126,44 +151,4 @@
|
|||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
|
||||||
const signInRules = @json($rules->keyBy('id'));
|
|
||||||
|
|
||||||
function openEditRule(id) {
|
|
||||||
const rule = signInRules[id];
|
|
||||||
if (!rule) return;
|
|
||||||
|
|
||||||
document.getElementById('edit-rule-form').action = `/admin/sign-in-rules/${id}`;
|
|
||||||
['streak_days', 'gold_reward', 'exp_reward', 'charm_reward', 'identity_badge_code',
|
|
||||||
'identity_badge_name', 'identity_badge_icon', 'identity_badge_color',
|
|
||||||
'identity_duration_days', 'sort_order'
|
|
||||||
].forEach((field) => {
|
|
||||||
const input = document.getElementById(`edit-${field}`);
|
|
||||||
if (input) input.value = rule[field] ?? '';
|
|
||||||
});
|
|
||||||
document.getElementById('edit-is-enabled').checked = Boolean(rule.is_enabled);
|
|
||||||
document.getElementById('edit-rule-modal').classList.remove('hidden');
|
|
||||||
}
|
|
||||||
|
|
||||||
function closeEditRule() {
|
|
||||||
document.getElementById('edit-rule-modal').classList.add('hidden');
|
|
||||||
}
|
|
||||||
|
|
||||||
async function toggleSignInRule(id) {
|
|
||||||
const response = await fetch(`/admin/sign-in-rules/${id}/toggle`, {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').content,
|
|
||||||
'Accept': 'application/json',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
const data = await response.json();
|
|
||||||
if (!response.ok || !data.ok) {
|
|
||||||
alert(data.message || '切换失败');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
window.location.reload();
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
@endsection
|
@endsection
|
||||||
|
|||||||
Reference in New Issue
Block a user