重构
This commit is contained in:
@@ -12,6 +12,8 @@ export interface SlipItem {
|
||||
oddsVersion: string;
|
||||
matchId: string;
|
||||
matchName: string;
|
||||
marketId?: string;
|
||||
marketName?: string;
|
||||
selectionName: string;
|
||||
odds: number;
|
||||
marketType: string;
|
||||
@@ -19,14 +21,28 @@ export interface SlipItem {
|
||||
allowParlay?: boolean;
|
||||
}
|
||||
|
||||
export const useBetSlipStore = defineStore('betSlip', () => {
|
||||
const items = ref<SlipItem[]>([]);
|
||||
const stake = ref<number>(10);
|
||||
const mode = ref<'single' | 'parlay'>('single');
|
||||
const lastParlayError = ref<ParlayRejectReason | 'MAX_LEGS' | null>(null);
|
||||
export type SlipMode = 'single' | 'parlay';
|
||||
export type ParlaySlipError = ParlayRejectReason | 'MAX_LEGS' | 'SAME_MATCH';
|
||||
|
||||
export const useBetSlipStore = defineStore('betSlip', () => {
|
||||
const singleItem = ref<SlipItem | null>(null);
|
||||
const parlayItems = ref<SlipItem[]>([]);
|
||||
const stake = ref<number>(5);
|
||||
const mode = ref<SlipMode>('single');
|
||||
const lastParlayError = ref<ParlaySlipError | null>(null);
|
||||
|
||||
const items = computed(() =>
|
||||
mode.value === 'parlay'
|
||||
? parlayItems.value
|
||||
: singleItem.value
|
||||
? [singleItem.value]
|
||||
: [],
|
||||
);
|
||||
const count = computed(() => items.value.length);
|
||||
const isParlay = computed(() => mode.value === 'parlay' && items.value.length >= PARLAY_MIN_LEGS);
|
||||
const parlayCount = computed(() => parlayItems.value.length);
|
||||
const singleCount = computed(() => (singleItem.value ? 1 : 0));
|
||||
const totalCount = computed(() => singleCount.value + parlayCount.value);
|
||||
const isParlay = computed(() => mode.value === 'parlay' && parlayItems.value.length >= PARLAY_MIN_LEGS);
|
||||
|
||||
function parseLineValue(v: number | string | null | undefined): number | null {
|
||||
if (v == null || v === '') return null;
|
||||
@@ -34,35 +50,33 @@ export const useBetSlipStore = defineStore('betSlip', () => {
|
||||
return Number.isFinite(n) ? n : null;
|
||||
}
|
||||
|
||||
/** 球赛/详情页:同场可多选,分笔单关;再点同一项可取消 */
|
||||
function addItem(item: SlipItem) {
|
||||
if (mode.value === 'parlay') items.value = [];
|
||||
mode.value = 'single';
|
||||
function setMode(nextMode: SlipMode) {
|
||||
mode.value = nextMode;
|
||||
lastParlayError.value = null;
|
||||
|
||||
const existing = items.value.findIndex(
|
||||
(i) => i.selectionId === item.selectionId,
|
||||
);
|
||||
if (existing >= 0) {
|
||||
items.value.splice(existing, 1);
|
||||
return;
|
||||
}
|
||||
items.value.push(item);
|
||||
}
|
||||
|
||||
/** 串关页:须为不同赛事,每场最多 1 项 */
|
||||
function addParlayLeg(item: SlipItem): ParlayRejectReason | 'MAX_LEGS' | null {
|
||||
if (mode.value === 'single') items.value = [];
|
||||
/** 球赛/详情页:点击任意选项后作为当前单注,打开投注抽屉 */
|
||||
function setSingleItem(item: SlipItem) {
|
||||
mode.value = 'single';
|
||||
singleItem.value = item;
|
||||
lastParlayError.value = null;
|
||||
}
|
||||
|
||||
function addItem(item: SlipItem) {
|
||||
setSingleItem(item);
|
||||
}
|
||||
|
||||
/** 串关:必须来自不同赛事,仍按盘口规则过滤不可串关项 */
|
||||
function addParlayLeg(item: SlipItem): ParlaySlipError | null {
|
||||
mode.value = 'parlay';
|
||||
|
||||
const samePick = items.value.findIndex((i) => i.selectionId === item.selectionId);
|
||||
const samePick = parlayItems.value.findIndex((i) => i.selectionId === item.selectionId);
|
||||
if (samePick >= 0) {
|
||||
items.value.splice(samePick, 1);
|
||||
lastParlayError.value = null;
|
||||
return null;
|
||||
}
|
||||
|
||||
if (items.value.some((i) => i.matchId === item.matchId)) {
|
||||
if (parlayItems.value.some((i) => i.matchId === item.matchId)) {
|
||||
lastParlayError.value = 'SAME_MATCH';
|
||||
return 'SAME_MATCH';
|
||||
}
|
||||
@@ -77,24 +91,52 @@ export const useBetSlipStore = defineStore('betSlip', () => {
|
||||
return check.reason;
|
||||
}
|
||||
|
||||
if (items.value.length >= PARLAY_MAX_LEGS) {
|
||||
if (parlayItems.value.length >= PARLAY_MAX_LEGS) {
|
||||
lastParlayError.value = 'MAX_LEGS';
|
||||
return 'MAX_LEGS';
|
||||
}
|
||||
|
||||
items.value.push(item);
|
||||
parlayItems.value.push(item);
|
||||
lastParlayError.value = null;
|
||||
return null;
|
||||
}
|
||||
|
||||
function addSingleToParlay(): ParlaySlipError | null {
|
||||
if (!singleItem.value) return null;
|
||||
return addParlayLeg(singleItem.value);
|
||||
}
|
||||
|
||||
function removeItem(selectionId: string) {
|
||||
items.value = items.value.filter((i) => i.selectionId !== selectionId);
|
||||
if (!items.value.length) mode.value = 'single';
|
||||
if (singleItem.value?.selectionId === selectionId) {
|
||||
singleItem.value = null;
|
||||
}
|
||||
parlayItems.value = parlayItems.value.filter((i) => i.selectionId !== selectionId);
|
||||
if (mode.value === 'parlay' && !parlayItems.value.length) mode.value = 'single';
|
||||
lastParlayError.value = null;
|
||||
}
|
||||
|
||||
function clearSingle() {
|
||||
singleItem.value = null;
|
||||
if (mode.value === 'single') lastParlayError.value = null;
|
||||
}
|
||||
|
||||
function clearParlay() {
|
||||
parlayItems.value = [];
|
||||
mode.value = 'single';
|
||||
lastParlayError.value = null;
|
||||
}
|
||||
|
||||
function clear() {
|
||||
items.value = [];
|
||||
if (mode.value === 'parlay') {
|
||||
clearParlay();
|
||||
return;
|
||||
}
|
||||
clearSingle();
|
||||
}
|
||||
|
||||
function clearAll() {
|
||||
singleItem.value = null;
|
||||
parlayItems.value = [];
|
||||
mode.value = 'single';
|
||||
lastParlayError.value = null;
|
||||
}
|
||||
@@ -111,22 +153,15 @@ export const useBetSlipStore = defineStore('betSlip', () => {
|
||||
return items.value.reduce((acc, i) => acc + stake.value * i.odds, 0);
|
||||
});
|
||||
|
||||
const hasSameMatch = computed(() => {
|
||||
const matchIds = items.value.map((i) => i.matchId);
|
||||
return new Set(matchIds).size !== matchIds.length;
|
||||
});
|
||||
|
||||
const canPlaceParlay = computed(
|
||||
() =>
|
||||
mode.value === 'parlay' &&
|
||||
items.value.length >= PARLAY_MIN_LEGS &&
|
||||
items.value.length <= PARLAY_MAX_LEGS &&
|
||||
!hasSameMatch.value,
|
||||
parlayItems.value.length >= PARLAY_MIN_LEGS &&
|
||||
parlayItems.value.length <= PARLAY_MAX_LEGS,
|
||||
);
|
||||
|
||||
/** 详情页等同场多笔单关(串关模式不走此路径) */
|
||||
const canPlaceBatchSingles = computed(
|
||||
() => mode.value === 'single' && items.value.length >= 1,
|
||||
() => mode.value === 'single' && singleItem.value != null,
|
||||
);
|
||||
|
||||
const canSubmit = computed(
|
||||
@@ -144,23 +179,33 @@ export const useBetSlipStore = defineStore('betSlip', () => {
|
||||
}
|
||||
|
||||
return {
|
||||
singleItem,
|
||||
parlayItems,
|
||||
items,
|
||||
stake,
|
||||
mode,
|
||||
singleCount,
|
||||
parlayCount,
|
||||
totalCount,
|
||||
count,
|
||||
isParlay,
|
||||
totalOdds,
|
||||
potentialReturn,
|
||||
hasSameMatch,
|
||||
canPlaceParlay,
|
||||
canPlaceBatchSingles,
|
||||
canSubmit,
|
||||
lastParlayError,
|
||||
drawerOpen,
|
||||
setMode,
|
||||
setSingleItem,
|
||||
addItem,
|
||||
addParlayLeg,
|
||||
addSingleToParlay,
|
||||
removeItem,
|
||||
clearSingle,
|
||||
clearParlay,
|
||||
clear,
|
||||
clearAll,
|
||||
openDrawer,
|
||||
closeDrawer,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user