老虎机三项修复:①来源label已有枚举(刷新即显中文) ②普通中奖/诅咒向本人发私聊通知+三7全服广播 ③FAB按钮支持拖动+位置localStorage持久化
This commit is contained in:
@@ -9,16 +9,24 @@
|
||||
- 最近记录展示
|
||||
--}}
|
||||
|
||||
{{-- ─── 老虎机悬浮按钮 ─── --}}
|
||||
<div id="slot-fab" x-data="slotFab()" x-show="visible" x-cloak
|
||||
style="position:fixed; bottom:150px; right:18px; z-index:9900;">
|
||||
<button x-on:click="openPanel()"
|
||||
style="width:52px; height:52px; border-radius:50%; border:none; cursor:pointer;
|
||||
{{-- ─── 老虎机悬浮按钮(可拖动) ─── --}}
|
||||
<div id="slot-fab"
|
||||
x-data="slotFab()"
|
||||
x-show="visible"
|
||||
x-cloak
|
||||
:style="'position:fixed; right:' + posX + 'px; bottom:' + posY + 'px; z-index:9900; touch-action:none; user-select:none;'"
|
||||
@pointerdown.prevent="startDrag($event)"
|
||||
@pointermove.window="onDrag($event)"
|
||||
@pointerup.window="endDrag($event)"
|
||||
@pointercancel.window="endDrag($event)">
|
||||
<button
|
||||
style="width:52px; height:52px; border-radius:50%; border:none;
|
||||
background:linear-gradient(135deg,#d97706,#f59e0b);
|
||||
box-shadow:0 4px 20px rgba(245,158,11,.5);
|
||||
font-size:22px; display:flex; align-items:center; justify-content:center;
|
||||
animation:slot-pulse 2s infinite;"
|
||||
title="老虎机">🎰</button>
|
||||
:style="dragging ? 'cursor:grabbing;' : 'cursor:grab;'"
|
||||
title="老虎机(可拖动)">🎰</button>
|
||||
</div>
|
||||
|
||||
{{-- ─── 老虎机主面板 ─── --}}
|
||||
@@ -259,15 +267,51 @@
|
||||
* 老虎机悬浮按钮 Alpine 组件(检查游戏是否开启)
|
||||
*/
|
||||
function slotFab() {
|
||||
const STORAGE_KEY = 'slot_fab_pos';
|
||||
const saved = JSON.parse(localStorage.getItem(STORAGE_KEY) || 'null');
|
||||
return {
|
||||
visible: false,
|
||||
visible: false,
|
||||
posX: saved?.x ?? 18,
|
||||
posY: saved?.y ?? 150,
|
||||
dragging: false,
|
||||
_startX: 0, _startY: 0,
|
||||
_origX: 0, _origY: 0,
|
||||
_moved: false,
|
||||
|
||||
async init() {
|
||||
try {
|
||||
const res = await fetch('/slot/info');
|
||||
const res = await fetch('/slot/info');
|
||||
const data = await res.json();
|
||||
this.visible = data.enabled === true;
|
||||
} catch {}
|
||||
},
|
||||
|
||||
startDrag(e) {
|
||||
this.dragging = true;
|
||||
this._moved = false;
|
||||
this._startX = e.clientX;
|
||||
this._startY = e.clientY;
|
||||
this._origX = this.posX;
|
||||
this._origY = this.posY;
|
||||
e.currentTarget.setPointerCapture?.(e.pointerId);
|
||||
},
|
||||
|
||||
onDrag(e) {
|
||||
if (!this.dragging) return;
|
||||
const dx = e.clientX - this._startX;
|
||||
const dy = e.clientY - this._startY;
|
||||
if (Math.abs(dx) > 3 || Math.abs(dy) > 3) this._moved = true;
|
||||
this.posX = Math.max(4, Math.min(window.innerWidth - 60, this._origX - dx));
|
||||
this.posY = Math.max(4, Math.min(window.innerHeight - 60, this._origY + dy));
|
||||
},
|
||||
|
||||
endDrag(e) {
|
||||
if (!this.dragging) return;
|
||||
this.dragging = false;
|
||||
localStorage.setItem(STORAGE_KEY, JSON.stringify({ x: this.posX, y: this.posY }));
|
||||
if (!this._moved) this.openPanel();
|
||||
},
|
||||
|
||||
openPanel() {
|
||||
const panel = document.getElementById('slot-panel');
|
||||
if (panel) Alpine.$data(panel).open();
|
||||
|
||||
Reference in New Issue
Block a user