删除 deposit.service 中重复的 getPlayerDepositOrder,避免 API 编译失败引发 500;快速下注弹层按卡片实例激活,同场赛事不再多处联动,移入快速下注区域时保持 VS 动画;记录列表改为整行可点,编号统一中性色样式。
102 lines
2.8 KiB
TypeScript
102 lines
2.8 KiB
TypeScript
import { ref } from 'vue';
|
|
import type { SlipItem } from '../stores/betSlip';
|
|
|
|
const visible = ref(false);
|
|
const anchorX = ref(0);
|
|
const anchorY = ref(0);
|
|
const pendingItem = ref<SlipItem | null>(null);
|
|
const activeCardRootId = ref<string | null>(null);
|
|
const placement = ref<'top' | 'bottom'>('bottom');
|
|
let closeTimer: number | undefined = undefined;
|
|
|
|
export function useDesktopBetPopover() {
|
|
function openAt(event: MouseEvent, item: SlipItem) {
|
|
cancelClose();
|
|
|
|
const el = (event.currentTarget || event.target) as HTMLElement;
|
|
const btn = el?.closest?.('button') || el;
|
|
const rect = btn?.getBoundingClientRect?.();
|
|
if (!rect) return;
|
|
|
|
const popW = 190;
|
|
const popH = 170;
|
|
const pad = 12; // increased pad to leave space for the arrow pointer
|
|
|
|
// Calculate center X of the button
|
|
const btnCenterX = rect.left + rect.width / 2;
|
|
let x = btnCenterX - popW / 2;
|
|
|
|
// Default: place below button (center bottom)
|
|
let y = rect.bottom + pad;
|
|
placement.value = 'bottom';
|
|
|
|
if (typeof window !== 'undefined') {
|
|
const spaceBelow = window.innerHeight - rect.bottom;
|
|
if (spaceBelow < popH + pad) {
|
|
// Not enough space below, place above button (center top)
|
|
y = rect.top - popH - pad;
|
|
placement.value = 'top';
|
|
}
|
|
|
|
// Keep within viewport boundaries
|
|
x = Math.max(pad, Math.min(x, window.innerWidth - popW - pad));
|
|
y = Math.max(pad, Math.min(y, window.innerHeight - popH - pad));
|
|
}
|
|
|
|
anchorX.value = x;
|
|
anchorY.value = y;
|
|
pendingItem.value = item;
|
|
const root = el?.closest?.('[data-bet-card-root]') as HTMLElement | null;
|
|
activeCardRootId.value = root?.dataset.betCardRoot ?? null;
|
|
visible.value = true;
|
|
}
|
|
|
|
function close() {
|
|
visible.value = false;
|
|
pendingItem.value = null;
|
|
activeCardRootId.value = null;
|
|
if (closeTimer !== undefined) {
|
|
window.clearTimeout(closeTimer);
|
|
closeTimer = undefined;
|
|
}
|
|
}
|
|
|
|
function scheduleClose(delay = 200) {
|
|
if (closeTimer !== undefined) {
|
|
window.clearTimeout(closeTimer);
|
|
}
|
|
closeTimer = window.setTimeout(() => {
|
|
visible.value = false;
|
|
pendingItem.value = null;
|
|
activeCardRootId.value = null;
|
|
closeTimer = undefined;
|
|
}, delay);
|
|
}
|
|
|
|
function cancelClose() {
|
|
if (closeTimer !== undefined) {
|
|
window.clearTimeout(closeTimer);
|
|
closeTimer = undefined;
|
|
}
|
|
}
|
|
|
|
function isActiveForCard(cardRootId: string | null | undefined) {
|
|
if (!cardRootId || !visible.value || !pendingItem.value) return false;
|
|
return activeCardRootId.value === cardRootId;
|
|
}
|
|
|
|
return {
|
|
visible,
|
|
anchorX,
|
|
anchorY,
|
|
pendingItem,
|
|
activeCardRootId,
|
|
placement,
|
|
openAt,
|
|
close,
|
|
scheduleClose,
|
|
cancelClose,
|
|
isActiveForCard,
|
|
};
|
|
}
|