diff --git a/resources/js/chat-room.js b/resources/js/chat-room.js index dc4c6ab..de86365 100644 --- a/resources/js/chat-room.js +++ b/resources/js/chat-room.js @@ -30,6 +30,7 @@ * - initial-state.js:恢复首屏历史消息、欢迎消息、入场特效和挂起婚姻事件。 * - bank-modal.js:处理银行弹窗、转账、排行和标签切换。 * - fishing.js:处理钓鱼入口与自动钓鱼相关交互。 + * - fortune-panel.js:提供神秘占卜 fortunePanel Alpine 组件。 * - profile-controls.js:处理用户资料和资料相关按钮。 * - shop-controls.js:处理商店弹窗的基础按钮事件。 * - slot-machine.js:提供老虎机 slotPanel/slotFab Alpine 组件。 @@ -102,6 +103,7 @@ export { toggleBankRankSort, } from "./chat-room/bank-modal.js"; export { bindFishingControls } from "./chat-room/fishing.js"; +export { bindFortunePanelControls, fortunePanel } from "./chat-room/fortune-panel.js"; export { bindProfileControls } from "./chat-room/profile-controls.js"; export { bindShopControls } from "./chat-room/shop-controls.js"; export { bindSlotMachineControls, slotFab, slotPanel } from "./chat-room/slot-machine.js"; @@ -193,6 +195,7 @@ import { toggleBankRankSort, } from "./chat-room/bank-modal.js"; import { bindFishingControls } from "./chat-room/fishing.js"; +import { bindFortunePanelControls, fortunePanel } from "./chat-room/fortune-panel.js"; import { bindProfileControls } from "./chat-room/profile-controls.js"; import { bindShopControls } from "./chat-room/shop-controls.js"; import { bindSlotMachineControls, slotFab, slotPanel } from "./chat-room/slot-machine.js"; @@ -298,6 +301,8 @@ if (typeof window !== "undefined") { switchBankTab, toggleBankRankSort, bindFishingControls, + bindFortunePanelControls, + fortunePanel, bindMarriageStatusControls, bindProfileControls, bindShopControls, @@ -376,6 +381,7 @@ if (typeof window !== "undefined") { window.closeBankModal = closeBankModal; window.closeGameHall = closeGameHall; window.fetchBankRanking = fetchBankRanking; + window.fortunePanel = fortunePanel; window.deferChatGameBootstrap = deferChatGameBootstrap; window.openGameHall = openGameHall; window.openBankModal = openBankModal; @@ -407,6 +413,7 @@ if (typeof window !== "undefined") { bindChatInitialStateControls(); bindBankControls(); bindFishingControls(); + bindFortunePanelControls(); bindMarriageStatusControls(); bindProfileControls(); bindShopControls(); diff --git a/resources/js/chat-room/fortune-panel.js b/resources/js/chat-room/fortune-panel.js new file mode 100644 index 0000000..43078f1 --- /dev/null +++ b/resources/js/chat-room/fortune-panel.js @@ -0,0 +1,173 @@ +// 聊天室神秘占卜游戏面板,提供 fortunePanel Alpine 组件和空闲初始化。 + +/** + * 读取 CSRF Token。 + * + * @returns {string} + */ +function csrf() { + return document.querySelector("meta[name=csrf-token]")?.content || ""; +} + +/** + * 创建神秘占卜面板 Alpine 组件。 + * + * @returns {object} + */ +export function fortunePanel() { + return { + show: false, + activeTab: "tell", + loading: false, + shaking: false, + freeCount: 1, + freeUsed: 0, + hasFreeLeft: true, + extraCost: 500, + todayLatest: null, + resultGrade: "", + resultLabel: "", + resultColor: "#a855f7", + resultText: "", + resultBuff: null, + historyLogs: [], + + /** + * 加载今日占卜状态。 + * + * @returns {Promise} + */ + async loadTodayStatus() { + try { + const response = await fetch("/fortune/today"); + const data = await response.json(); + if (!data.enabled) { + return; + } + + this.freeCount = data.free_count || 1; + this.freeUsed = data.free_used || 0; + this.hasFreeLeft = data.has_free_left ?? true; + this.extraCost = data.extra_cost || 500; + this.todayLatest = data.latest || null; + } catch (error) { + // 占卜状态失败不影响聊天室主流程。 + } + }, + + /** + * 执行一次占卜。 + * + * @returns {Promise} + */ + async doFortune() { + if (this.loading) { + return; + } + + this.loading = true; + this.shaking = true; + + // 摇卦动画先播放,再请求服务端结果,保持旧版节奏。 + await new Promise((resolve) => window.setTimeout(resolve, 600)); + this.shaking = false; + + try { + const response = await fetch("/fortune/tell", { + method: "POST", + headers: { + "Content-Type": "application/json", + "Accept": "application/json", + "X-CSRF-TOKEN": csrf(), + }, + }); + const data = await response.json(); + + if (data.ok) { + this.resultGrade = data.grade; + this.resultLabel = data.grade_label; + this.resultColor = data.grade_color; + this.resultText = data.text; + this.resultBuff = data.buff_desc; + + // 免费次数只在服务端确认免费占卜成功后本地递增。 + if (data.is_free) { + this.freeUsed += 1; + this.hasFreeLeft = this.freeUsed < this.freeCount; + } + return; + } + + window.chatDialog?.alert?.(data.message || "占卜失败", "提示", "#ef4444"); + } catch (error) { + window.chatDialog?.alert?.("网络异常,请稍后重试。", "错误", "#ef4444"); + } finally { + this.loading = false; + } + }, + + /** + * 加载占卜历史记录。 + * + * @returns {Promise} + */ + async loadHistory() { + if (this.historyLogs.length > 0) { + return; + } + + try { + const response = await fetch("/fortune/history"); + const data = await response.json(); + this.historyLogs = data.history || []; + } catch (error) { + this.historyLogs = []; + } + }, + }; +} + +/** + * 空闲时预加载今日占卜状态。 + * + * @returns {void} + */ +function scheduleFortuneBootstrap() { + document.addEventListener("DOMContentLoaded", () => window.deferChatGameBootstrap?.(async () => { + try { + const response = await fetch("/fortune/today"); + const data = await response.json(); + if (!data.enabled) { + return; + } + + const panel = document.getElementById("fortune-panel"); + if (!panel || !window.Alpine) { + return; + } + + const panelData = window.Alpine.$data(panel); + panelData.freeCount = data.free_count || 1; + panelData.freeUsed = data.free_used || 0; + panelData.hasFreeLeft = data.has_free_left ?? true; + panelData.extraCost = data.extra_cost || 500; + panelData.todayLatest = data.latest || null; + } catch (error) { + console.warn("[神秘占卜] 初始化失败", error); + } + })); +} + +/** + * 绑定神秘占卜全局 Alpine 工厂函数。 + * + * @returns {void} + */ +export function bindFortunePanelControls() { + if (typeof window === "undefined") { + return; + } + + window.fortunePanel = fortunePanel; + scheduleFortuneBootstrap(); +} diff --git a/resources/views/chat/partials/games/fortune-panel.blade.php b/resources/views/chat/partials/games/fortune-panel.blade.php index 9196a3c..0a510d4 100644 --- a/resources/views/chat/partials/games/fortune-panel.blade.php +++ b/resources/views/chat/partials/games/fortune-panel.blade.php @@ -248,131 +248,4 @@ } - +{{-- 神秘占卜 Alpine 组件已迁移到 resources/js/chat-room/fortune-panel.js --}}