- 管理端按联赛展示单场,新增赛事/单场流程与列表展开状态保持 - 盘口赔率迁至独立页面,保存按钮仅在有修改时高亮 - API 新增联赛列表与子场查询,按 locale 返回队名并修复编译 - 波胆其它选项与促销标签等 i18n 补齐,文案更易懂
108 lines
2.7 KiB
Vue
108 lines
2.7 KiB
Vue
<script setup lang="ts">
|
|
import { ref, computed, watch } from 'vue';
|
|
import { useRoute, useRouter } from 'vue-router';
|
|
import { ElMessage } from 'element-plus';
|
|
import { useAdminLocale } from '../../composables/useAdminLocale';
|
|
import api from '../../api';
|
|
import MatchMarketsPanel from './MatchMarketsPanel.vue';
|
|
import type { AdminMatchDetail } from '../match-form.ts';
|
|
|
|
const route = useRoute();
|
|
const router = useRouter();
|
|
const { t } = useAdminLocale();
|
|
|
|
const matchId = computed(() => String(route.params.matchId ?? ''));
|
|
const loading = ref(false);
|
|
const status = ref('DRAFT');
|
|
const matchLabel = ref('');
|
|
|
|
async function load() {
|
|
if (!matchId.value) return;
|
|
loading.value = true;
|
|
try {
|
|
const { data } = await api.get(`/admin/matches/${matchId.value}`);
|
|
const detail = data.data as AdminMatchDetail;
|
|
if (detail.isOutright) {
|
|
ElMessage.warning(t('msg.outright_no_edit'));
|
|
router.replace('/outrights');
|
|
return;
|
|
}
|
|
status.value = detail.status;
|
|
const home = detail.homeTeamZh || detail.homeTeamEn || detail.homeTeamCode || '';
|
|
const away = detail.awayTeamZh || detail.awayTeamEn || detail.awayTeamCode || '';
|
|
matchLabel.value =
|
|
detail.matchName?.trim() ||
|
|
(home && away ? `${home} vs ${away}` : `#${matchId.value}`);
|
|
} catch (e: unknown) {
|
|
const err = e as { response?: { data?: { error?: string } } };
|
|
ElMessage.error(err.response?.data?.error ?? t('msg.load_failed'));
|
|
} finally {
|
|
loading.value = false;
|
|
}
|
|
}
|
|
|
|
watch(matchId, load, { immediate: true });
|
|
</script>
|
|
|
|
<template>
|
|
<div v-loading="loading" class="match-markets-page page-scroll">
|
|
<div class="editor-topbar">
|
|
<el-button size="small" text class="back-btn" @click="router.push('/matches')">
|
|
← {{ t('matchEditor.back') }}
|
|
</el-button>
|
|
<div class="topbar-title">
|
|
<h2>{{ t('matchEditor.section_markets') }}</h2>
|
|
<span class="match-subtitle">{{ matchLabel }}</span>
|
|
<el-tag size="small" type="info">{{ t(`match.status.${status}`) }}</el-tag>
|
|
</div>
|
|
</div>
|
|
|
|
<section v-if="matchId" class="panel">
|
|
<MatchMarketsPanel :match-id="matchId" />
|
|
</section>
|
|
</div>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.match-markets-page {
|
|
padding: 0 4px 24px;
|
|
}
|
|
|
|
.editor-topbar {
|
|
display: flex;
|
|
align-items: flex-start;
|
|
gap: 12px;
|
|
margin-bottom: 16px;
|
|
}
|
|
|
|
.back-btn {
|
|
flex-shrink: 0;
|
|
padding-left: 0 !important;
|
|
}
|
|
|
|
.topbar-title {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
align-items: center;
|
|
gap: 8px;
|
|
}
|
|
|
|
.topbar-title h2 {
|
|
margin: 0;
|
|
font-size: 18px;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.match-subtitle {
|
|
color: var(--green-text);
|
|
font-size: 14px;
|
|
}
|
|
|
|
.panel {
|
|
background: #111;
|
|
border: 1px solid #2a2a2a;
|
|
border-radius: 12px;
|
|
overflow: hidden;
|
|
}
|
|
</style>
|