feat: split admin dashboard, improve match ops, and player closed-match UX
Admin: add match/player overview sub-nav; refine settlement flow and league match management UI; improve action button enabled/disabled styles; enhance logo upload and outright odds sync. API: expose matchPhase/bettingOpen for closed matches; league publish guards; settlement preview with auto score save; outright team auto-sync. Player: watermark for closed/settled states; keep match and bet details visible; remove default login credentials. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -3,6 +3,8 @@ import { computed } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { formatMoney } from '../utils/localeDisplay';
|
||||
import StatusWatermark from './StatusWatermark.vue';
|
||||
import { matchPhaseLabel, matchPhaseVariant, type MatchPhase } from '../utils/matchPhase';
|
||||
|
||||
export interface BetScore {
|
||||
ht: string | null;
|
||||
@@ -24,6 +26,7 @@ export interface BetHistoryItem {
|
||||
isParlay?: boolean;
|
||||
legCount?: number;
|
||||
matchScore?: BetScore | null;
|
||||
matchPhase?: MatchPhase | null;
|
||||
legs?: Array<{
|
||||
marketLabel: string;
|
||||
selectionName: string;
|
||||
@@ -48,6 +51,22 @@ const statusKey = computed(() => {
|
||||
|
||||
const statusLabel = computed(() => t(`history.status_${statusKey.value}`));
|
||||
|
||||
const watermarkLabel = computed(() => {
|
||||
if (statusKey.value === 'pending' && props.bet.matchPhase === 'closed_pending') {
|
||||
return matchPhaseLabel(t, 'closed_pending');
|
||||
}
|
||||
if (statusKey.value === 'pending' && props.bet.matchPhase === 'settled') {
|
||||
return matchPhaseLabel(t, 'settled');
|
||||
}
|
||||
return statusLabel.value;
|
||||
});
|
||||
|
||||
const watermarkVariant = computed(() => {
|
||||
if (statusKey.value === 'pending' && props.bet.matchPhase === 'closed_pending') return 'closed';
|
||||
if (statusKey.value === 'pending' && props.bet.matchPhase === 'settled') return 'settled';
|
||||
return statusKey.value;
|
||||
});
|
||||
|
||||
const placedDate = computed(() =>
|
||||
new Date(props.bet.placedAt).toLocaleDateString(locale.value, {
|
||||
month: 'short', day: 'numeric',
|
||||
@@ -87,10 +106,7 @@ function goDetail() {
|
||||
|
||||
<template>
|
||||
<article class="bet-card" @click="goDetail">
|
||||
<span
|
||||
class="watermark"
|
||||
:class="statusKey"
|
||||
>{{ statusLabel }}</span>
|
||||
<StatusWatermark :label="watermarkLabel" :variant="watermarkVariant" />
|
||||
<div class="card-left">
|
||||
<span class="title">{{ title }}</span>
|
||||
<span class="subtitle">{{ subtitle }} · {{ placedDate }}</span>
|
||||
@@ -125,28 +141,6 @@ function goDetail() {
|
||||
background: rgba(255, 255, 255, 0.02);
|
||||
}
|
||||
|
||||
.watermark {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%) rotate(-35deg);
|
||||
font-size: 28px;
|
||||
font-weight: 900;
|
||||
letter-spacing: 0.06em;
|
||||
white-space: nowrap;
|
||||
pointer-events: none;
|
||||
text-transform: uppercase;
|
||||
opacity: 0.18;
|
||||
max-width: 90%;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.watermark.won { color: #3db865; }
|
||||
.watermark.lost { color: #e05050; }
|
||||
.watermark.push { color: #888; }
|
||||
.watermark.pending { color: #e8c84a; }
|
||||
|
||||
.card-left {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
|
||||
Reference in New Issue
Block a user