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:
2026-06-10 13:00:14 +08:00
parent 6124313369
commit 03f54ca689
43 changed files with 2787 additions and 519 deletions

View File

@@ -6,6 +6,8 @@ import api from '../api';
import { formatMoney } from '../utils/localeDisplay';
import GoldSpinner from '../components/GoldSpinner.vue';
import { usePullToRefresh } from '../composables/usePullToRefresh';
import StatusWatermark from '../components/StatusWatermark.vue';
import { matchPhaseLabel, matchPhaseVariant, type MatchPhase } from '../utils/matchPhase';
import type { BetHistoryItem } from '../components/BetHistoryCard.vue';
const route = useRoute();
@@ -122,6 +124,12 @@ const myPick = computed(() => {
if (ci < 0) return raw;
return raw.slice(0, ci + 2) + translateSel(raw.slice(ci + 2));
});
const matchPhase = computed(
(): MatchPhase | null => bet.value?.matchPhase ?? null,
);
const matchPhaseText = computed(() => matchPhaseLabel(t, matchPhase.value));
</script>
<template>
@@ -164,7 +172,13 @@ const myPick = computed(() => {
<div class="match-name">{{ matchTitle }}</div>
<!-- single bet: score comparison -->
<div v-if="!bet.isParlay" class="score-block">
<div v-if="!bet.isParlay" class="score-block" :class="{ 'score-block--phase': matchPhase && matchPhase !== 'open' }">
<StatusWatermark
v-if="matchPhase && matchPhase !== 'open'"
:label="matchPhaseText"
:variant="matchPhaseVariant(matchPhase)"
size="md"
/>
<!-- my pick row -->
<div class="row-label-val">
<span class="row-label">{{ t('history.my_pick') }}</span>
@@ -364,11 +378,17 @@ const myPick = computed(() => {
/* score block */
.score-block {
position: relative;
overflow: hidden;
display: flex;
flex-direction: column;
gap: 8px;
}
.score-block--phase {
padding: 8px 0 4px;
}
.row-label-val {
display: flex;
justify-content: space-between;