feat(admin+api+player): 优胜赛结算态、禁止新增单场与钱包流水展示优化
- API/管理端:优胜赛 SETTLED 后禁止新增单场,列表与子页展示结算状态 - 玩家端:已结算 outright 只读展示并高亮冠军 - 管理端:结算后 stale 标记驱动列表刷新;财务流水时间与备注 i18n 优化 - shared:txDisplayAmount 与 LEAGUE_OUTRIGHT_SETTLED 错误码
This commit is contained in:
@@ -3,6 +3,7 @@ import { ref, computed, watch, onBeforeUnmount, onDeactivated } from 'vue';
|
||||
|
||||
defineOptions({ name: 'AdminMatches' });
|
||||
import { useStaleListLifecycle } from '../composables/useStaleList';
|
||||
import { consumeAdminListStale } from '../utils/adminListStale';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { useAdminLocale } from '../composables/useAdminLocale';
|
||||
import { resolveFormError } from '../i18n/form-validation';
|
||||
@@ -38,6 +39,7 @@ const isMatchChildRoute = computed(() =>
|
||||
interface LeagueTableRow extends Record<string, unknown> {
|
||||
id: string;
|
||||
isPublished: boolean;
|
||||
isOutrightSettled: boolean;
|
||||
isPublishing: boolean;
|
||||
labels: {
|
||||
edit: string;
|
||||
@@ -50,7 +52,7 @@ interface LeagueTableRow extends Record<string, unknown> {
|
||||
displayNameZh: string;
|
||||
displayNameEn: string;
|
||||
displayStatusLabel: string;
|
||||
displayStatusTagType: 'success' | 'info';
|
||||
displayStatusTagType: 'success' | 'info' | 'warning';
|
||||
displayMatchCount: number;
|
||||
displayBetCount: number;
|
||||
displayBetCountActive: boolean;
|
||||
@@ -121,6 +123,7 @@ function mapLeagueRows(items: unknown[], publishingId = ''): LeagueTableRow[] {
|
||||
const r = rowOf(item);
|
||||
const id = String(r.id ?? '');
|
||||
const published = Boolean(r.isPublished);
|
||||
const outrightSettled = Boolean(r.isOutrightSettled);
|
||||
const stats = r.betStats as
|
||||
| { betCount?: number; totalStake?: string; pendingCount?: number }
|
||||
| undefined;
|
||||
@@ -129,13 +132,18 @@ function mapLeagueRows(items: unknown[], publishingId = ''): LeagueTableRow[] {
|
||||
...r,
|
||||
id,
|
||||
isPublished: published,
|
||||
isOutrightSettled: outrightSettled,
|
||||
isPublishing: publishingId === id,
|
||||
labels,
|
||||
displaySeq: start + index + 1,
|
||||
displayNameZh: String(r.leagueZh ?? '').trim() || '—',
|
||||
displayNameEn: String(r.leagueEn ?? '').trim() || '—',
|
||||
displayStatusLabel: published ? t('league.status.PUBLISHED') : t('league.status.UNPUBLISHED'),
|
||||
displayStatusTagType: published ? 'success' : 'info',
|
||||
displayStatusLabel: outrightSettled
|
||||
? t('league.status.OUTRIGHT_SETTLED')
|
||||
: published
|
||||
? t('league.status.PUBLISHED')
|
||||
: t('league.status.UNPUBLISHED'),
|
||||
displayStatusTagType: outrightSettled ? 'warning' : published ? 'success' : 'info',
|
||||
displayMatchCount: Number(r.matchCount ?? 0),
|
||||
displayBetCount: betCount,
|
||||
displayBetCountActive: betCount > 0,
|
||||
@@ -163,6 +171,7 @@ function persistListUiState() {
|
||||
type LoadOptions = { restore?: boolean };
|
||||
|
||||
async function load(options: LoadOptions = {}) {
|
||||
consumeAdminListStale();
|
||||
const saved = options.restore ? readMatchesListUiState() : null;
|
||||
if (saved) {
|
||||
page.value = saved.page;
|
||||
@@ -189,6 +198,17 @@ function onSearch() {
|
||||
void runLoad(true);
|
||||
}
|
||||
|
||||
const MATCH_CHILD_ROUTE = /^\/matches\/leagues\/[^/]+/;
|
||||
|
||||
watch(
|
||||
() => route.path,
|
||||
(path, prevPath) => {
|
||||
if (prevPath && MATCH_CHILD_ROUTE.test(prevPath) && path === '/matches') {
|
||||
void load();
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
async function initialLoad() {
|
||||
if (isMatchChildRoute.value) return;
|
||||
const qStatus = route.query.status;
|
||||
|
||||
Reference in New Issue
Block a user