// 赛马竞猜悬浮按钮组件,负责拖动位置持久化和打开赛马面板。 const HORSE_RACE_FAB_STORAGE_KEY = "horse_race_fab_pos"; /** * 安全读取赛马悬浮按钮保存的位置。 * * @returns {{x?: number, y?: number}|null} */ function readSavedHorseRaceFabPosition() { try { return JSON.parse(localStorage.getItem(HORSE_RACE_FAB_STORAGE_KEY) || "null"); } catch (error) { return null; } } /** * 创建赛马竞猜悬浮按钮 Alpine 组件。 * * @returns {Record} */ export function horseRaceFab() { const saved = readSavedHorseRaceFabPosition(); return { visible: false, posX: saved?.x ?? 80, posY: saved?.y ?? 90, dragging: false, _startX: 0, _startY: 0, _origX: 0, _origY: 0, _moved: false, /** * 开始拖动赛马悬浮按钮。 * * @param {PointerEvent} event 指针事件 * @returns {void} */ startDrag(event) { this.dragging = true; this._moved = false; this._startX = event.clientX; this._startY = event.clientY; this._origX = this.posX; this._origY = this.posY; event.currentTarget.setPointerCapture?.(event.pointerId); }, /** * 拖动过程中约束按钮不超出视口。 * * @param {PointerEvent} event 指针事件 * @returns {void} */ onDrag(event) { if (!this.dragging) { return; } const dx = event.clientX - this._startX; const dy = event.clientY - this._startY; if (Math.abs(dx) > 3 || Math.abs(dy) > 3) { this._moved = true; } // 赛马按钮使用 right/bottom 定位,拖动方向需要反向换算。 this.posX = Math.max(4, Math.min(window.innerWidth - 132, this._origX - dx)); this.posY = Math.max(4, Math.min(window.innerHeight - 132, this._origY - dy)); }, /** * 结束拖动;没有移动时按点击处理并打开赛马面板。 * * @returns {void} */ endDrag() { if (!this.dragging) { return; } this.dragging = false; localStorage.setItem(HORSE_RACE_FAB_STORAGE_KEY, JSON.stringify({ x: this.posX, y: this.posY, })); if (!this._moved) { this.openPanel(); } }, /** * 打开赛马主面板。 * * @returns {void} */ openPanel() { const panel = document.getElementById("horse-race-panel"); if (!panel || typeof window.Alpine?.$data !== "function") { return; } window.Alpine.$data(panel).openFromHall(); }, }; } /** * 挂载赛马悬浮按钮全局组件名,兼容 Blade 的 x-data。 * * @returns {void} */ export function bindHorseRaceFabControls() { if (typeof window === "undefined") { return; } window.horseRaceFab = horseRaceFab; }